Yapıcı veya ayarlayıcı yöntemi kullanılsın mı?


16

Ben bir Actionsınıf, böyle bir şey var bir UI kodu üzerinde çalışıyorum -

public class MyAction extends Action {
    public MyAction() {
        setText("My Action Text");
        setToolTip("My Action Tool tip");
        setImage("Some Image");
    }
}

Bu Action sınıfı oluşturulduğunda, Actionsınıfın özelleştirilemeyeceği varsayılmıştır (bir anlamda - metni, araç ipucu veya görüntüsü kodun hiçbir yerinde değiştirilmeyecektir). Şimdi, kodun bir noktasında eylem metnini değiştirmemiz gerekiyor. Bu nedenle, iş arkadaşımın sabit kodlu eylem metnini kurucudan kaldırmasını ve bağımsız değişken olarak kabul etmesini önerdim, böylece herkes eylem metnini iletmeye zorlanır. Aşağıdaki bu kod gibi bir şey -

public class MyAction extends Action {
    public MyAction(String actionText) {
        setText(actionText);
        setTooltip("My Action tool tip"); 
        setImage("My Image"); 
    }
}

Bununla birlikte, setText()yöntem temel sınıfa ait olduğu için, eylem metninin oluşturulduğu her yerde eylem metnini geçirmek için esnek bir şekilde kullanılabileceğini düşünmektedir. Bu şekilde, mevcut MyActionsınıfı değiştirmeye gerek yoktur . Yani kodu böyle bir şey olurdu.

MyAction action = new MyAction(); //this creates action instance with the hardcoded text
action.setText("User required new action text"); //overwrite the existing text.

Bunun sorunla başa çıkmanın doğru yolu olup olmadığından emin değilim. Yukarıda belirtilen durumda kullanıcı yine de metni değiştireceğini düşünüyorum, bu yüzden neden eylem inşa ederken onu zorlamıyor? Orijinal kodla gördüğüm tek fayda, kullanıcının metin ayarlamayı düşünmeden Action sınıfı oluşturabilmesidir.


1
Kullandığınız dil, aşırı yük oluşturucularına izin vermiyor mu?
Mat

1
Java kullanıyorum. Evet, izin veriyor ve bununla başa çıkmanın bir yolu olabileceğini düşünüyorum
zswap 29:12

2
Eğer bundan sonra sınıf üyelerini ayarlamak için halka açık bir yolunuz yoksa, sınıfınızın etkili bir şekilde değişmez olduğunu belirtmek isterim . Bir kamu ayarlayıcısına izin vererek, sınıfınız şimdi değişebilir hale gelir ve değişmezliğe bağlıysanız bunu göz önünde bulundurmanız gerekebilir.
cbojar

Nesnenizin geçerli olması için ayarlanması gerekiyorsa, her yapıcıya koyun ... isteğe bağlıysa (makul bir varsayılanı varsa) ve değişmezliği umursamıyorsanız, bir ayarlayıcıya koyun. Nesnenizi geçersiz bir duruma veya örneklemeden sonra mümkün olduğunca geçersiz bir duruma getirmeniz mümkün olmamalıdır.
Bill K

Yanıtlar:


15

Orijinal kodla gördüğüm tek fayda, kullanıcının metin ayarlamayı düşünmeden Action sınıfı oluşturabilmesidir.

Bu aslında bir fayda değil, çoğu amaç için bir dezavantaj ve geri kalan durumlarda ona kravat derim. Birisi inşaattan sonra setText () öğesini çağırmayı unutursa ne olur? Ya alışılmadık bir durumda, belki de bir hata işleyicide durum buysa? Metni gerçekten ayarlanmaya zorlamak istiyorsanız, derleme zamanında zorlamanız gerekir, çünkü yalnızca derleme zamanı hataları gerçekten ölümcüldür . Çalışma zamanında gerçekleşen her şey yürütülen belirli kod yoluna bağlıdır.

İleride iki net yol görüyorum:

  1. Önerdiğiniz gibi bir yapıcı parametresi kullanın. Gerçekten istiyorsanız, geçebilir nullveya boş bir dize olabilir, ancak daha sonra bir metin atamadığınız gerçeği, örtük olmaktan ziyade açıktır . Bir nullparametrenin varlığını görmek ve muhtemelen bazı düşüncelerin olduğunu görmek kolaydır, ancak bir yöntem çağrısının eksikliğini görmek ve böyle bir eksikliğin kasıtlı olup olmadığını belirlemek o kadar kolay değildir. Böyle basit bir vaka için, bu muhtemelen benim alacağım yaklaşımdır.
  2. Bir fabrika / üretici kalıbı kullanın. Bu, bu kadar basit bir senaryo için aşırı olabilir, ancak daha genel bir durumda, herhangi bir sayıda parametre ayarlamanıza ve nesne başlatmadan önce veya sırasında önkoşulları kontrol etmenize izin verdiği için oldukça esnektir (nesneyi oluşturmak büyük bir işlemse ve / veya sınıf birden fazla şekilde kullanılabilir, bu çok büyük bir avantaj olabilir). Özellikle Java'da da yaygın bir deyimdir ve kullandığınız dilde ve çerçevede yerleşik kalıpları takip etmek çok nadiren kötü bir şeydir.

10

Yapıcı aşırı yüklemesi burada basit ve basit bir çözüm olacaktır:

public class MyAction extends Action {
    public MyAction(String actionText) {
        setText(actionText);
        setTooltip("My Action tool tip"); 
        setImage("My Image"); 
    }
    public MyAction() {
        this("My Action Text");
    }
}

Daha .setTextsonra aramaktan daha iyidir , çünkü bu şekilde hiçbir şeyin üzerine yazılmasına gerek yoktur, actionTextbaşlangıçtan itibaren amaçlanan şey olabilir.

Kodunuz geliştikçe ve daha da fazla esnekliğe ihtiyacınız olacak (ki kesinlikle olacak), başka bir cevap tarafından önerilen fabrika / inşaatçı modelinden yararlanacaksınız.


İkinci bir mülkü özelleştirmek istediklerinde ne olur?
kevin cline

3
2., 3., .. özellikleri için aynı tekniği uygulayabilirsiniz, ancak ne kadar fazla özellik özelleştirmek isterseniz, bu o kadar uygunsuz olur. Bir noktada, bir fabrika / inşaatçı modelinin uygulanması daha mantıklı olacaktır, ayrıca cevabında @ michael-kjorling de söyledi.
janos

6

Akıcı bir 'setText' yöntemi ekleyin:

public class MyAction ... {
  ...
  public MyAction setText(String text) { ... ; return this; }
}

MyAction a = new MyAction().setText("xxx");

Bundan daha net ne olabilir? Başka bir özelleştirilebilir özellik eklemeye karar verirseniz, sorun değil.


+1, katılıyorum ve daha fazla mülkle tamamlayıcı bir yanıt daha ekledim. Akıcı API'nin örnek olarak 1'den fazla tek mülkünüz olduğunda anlaşılması daha kolay olduğunu düşünüyorum.
Machado

Akıcı arayüzleri seviyorum, özellikle değişmez nesneler üreten inşaatçılar için! Daha fazla parametre, daha iyi çalışır. Ancak bu sorudaki belirli örneğe baktığımda, setText()bunun MyAction'ın devraldığı Action sınıfında tanımlandığını tahmin ediyorum . Büyük olasılıkla geçersiz bir dönüş türüne sahiptir.
GlenPeterson

1

Kevin Cline'ın cevabında söylediği gibi , gitmenin yolunun akıcı bir API oluşturmak olduğunu düşünüyorum . Sadece akıcı API'nın kullanabileceğiniz birden fazla mülkünüz olduğunda daha iyi çalıştığını eklemek istiyorum.

Kodunuzu daha okunabilir hale getirecek ve benim açımdan daha kolay ve aham , "seksi" yazmak için.

Senin durumunda böyle gider (herhangi bir yazım hatası için üzgünüm, son java programımı yazdığımdan beri bir yıl oldu):

 public class MyAction extends Action {
    private String _text     = "";
    private String _tooltip  = "";
    private String _imageUrl = "";

    public MyAction()
    {
       // nothing to do here.
    }

    public MyAction text(string value)
    {
       this._text = value;
       return this;
    }

    public MyAction tooltip(string value)
    {
       this._tooltip = value;
       return this;
    }

    public MyAction image(string value)
    {
       this._imageUrl = value;
       return this;
    }
}

Ve kullanım şöyle olurdu:

MyAction action = new MyAction()
    .text("My Action Text")
    .tooltip("My Action Tool tip")
    .image("Some Image");

Kötü fikir, ya metin ya da önemli bir şey ayarlamayı unuturlarsa.
Prakhar

1

İnşaatçıları veya inşaatçıları kullanma tavsiyesi genel olarak iyidir, ancak, benim deneyimime göre, Eylemler için bazı önemli noktaları kaçırıyor.

  1. Muhtemelen uluslararası hale getirilmesi gerekiyor
  2. Pazarlamanın son dakikada değişmesi muhtemeldir.

Kesinlikle ad, araç ipucu, simge vb bir özellikler dosyasından, XML, vb okunmasını öneririz. Örneğin, Dosya Aç eylem için, bir Özellikler iletebilir ve

File.open.name=Open
File.open.tooltip=Open a file
File.open.icon=somedir/open.jpg

Bu, daha iyi bir simge, vb denemek için Fransızcaya çevirmek oldukça kolay bir formattır. Programcı zamanı veya yeniden derleme olmadan.

Bu sadece kaba bir taslak, okuyucuya çok şey kaldı ... Diğer uluslararasılaştırma örneklerine bakın.


0

Yapıcı içinde setText (actionText) veya setTooltip ("Eylem aracımın ipucu") çağırmak işe yaramaz; ilgili alanı doğrudan başlatırsanız daha kolaydır (ve daha fazla performans kazanırsınız):

    public MyAction(String actionText) {
        this.actionText = actionText;
    }

ActionText'i karşılık gelen MyAction nesnesinin yaşam süresi boyunca değiştirirseniz, bir ayarlayıcı yöntemi yerleştirmelisiniz; alan bir ayarlayıcı yöntemi sağlamadan yalnızca kurucuda başlatılmazsa.

Araç ipucu ve resim sabit olduğu için bunları sabit olarak kabul edin; alanları var:

private (or even public) final static String TOOLTIP = "My Action Tooltip";

Aslında, ortak nesneler tasarlarken (kesinlikle veri yapılarını temsil eden fasulye veya nesneler değil), ayarlayıcılara ve alıcılara bir tür kırılma kapsüllemesi sağlamak kötü bir fikirdir.


4
Herhangi bir yarı-yollu derleyici ve JITter, setText () vb çağrılarını satır içine almalıdır; bu nedenle, bir atama yapmak için bir işlev çağrısı ile bu çağrıyı işlev çağrısı yerine sahip olmak arasındaki performans farkı en fazla ihmal edilebilir ve daha olasıdır sıfır değil.
CVn

0

Ben genel bir eylem sınıfı (Çalışan, Bölüm güncellemek için kullanılan güncelleme gibi) yapacaksanız bu doğru olduğunu düşünüyorum. Her şey senaryoya bağlı. Belirli bir eylem (güncelleme çalışanı gibi) sınıfı (uygulamada birçok yer kullanılır - Çalışanı güncelle), uygulamanın her yerinde aynı tutarlılığı, araç ipucunu ve görüntüyü tutmak amacıyla oluşturulur (tutarlılık açısından). Böylece varsayılan metin, araç ipucu ve görüntü sağlamak için metin, araç ipucu ve görüntü için sabit kodlama yapılabilir. Yine de daha fazla esneklik sağlamak için, bunları özelleştirmek için karşılık gelen ayarlayıcı yöntemlere sahip olmalıdır. Aklımızda sadece% 10 yer değiştirmek zorundayız. Kullanıcıdan her seferinde eylem metni almak, aynı eylem için her seferinde Farklı metinlere neden olabilir. 'Çalışanları Güncelle', 'Çalışanları Güncelle', 'Çalışanları Değiştir' veya 'Çalışanları Düzenle' gibi.


Aşırı yüklenmiş yapıcı hala sorunu çözmek gerektiğini düşünüyorum. Çünkü tüm "% 10" durumlarda, önce varsayılan metin içeren bir Eylem oluşturacak ve daha sonra "setText ()" yöntemini kullanarak eylem metnini değiştireceksiniz. Eylemi oluştururken neden uygun metni ayarlamıyorsunuz?
zswap

0

Örneklerin nasıl kullanılacağını düşünün ve kullanıcıları bu örnekleri doğru veya en azından en iyi şekilde kullanmaya yönlendirecek, hatta zorlayacak bir çözüm kullanın. Bu sınıfı kullanan bir programcının endişelenecek ve düşünecek çok daha fazla şeyi olacaktır. Bu sınıf listeye eklenmemelidir.

Örneğin, MyAction sınıfının inşaattan sonra değişmez olması gerekiyorsa (ve muhtemelen başka bir başlatma), bir ayarlayıcı yöntemi olmamalıdır. Çoğu zaman varsayılan "Eylem Metnim" i kullanacaksa, parametresiz bir kurucu ve isteğe bağlı bir metne izin veren bir kurucu olmalıdır. Artık kullanıcının sınıfı% 90 oranında doğru kullanmayı düşünmesi gerekmiyor. Genellikle kullanıcı varsa gerektiğini metne biraz düşünmek, parametresiz yapıcı atlayın. Artık kullanıcı gerektiğinde düşünmek zorunda kalıyor ve gerekli bir adımı göz ardı edemiyor.

Bir MyActionörneğin tam inşaattan sonra değiştirilebilir olması gerekiyorsa, metin için bir ayarlayıcıya ihtiyacınız vardır. Yapıcıdaki değeri ayarlamayı atlamak caziptir (KURU prensibi - "Kendinizi Tekrarlamayın") ve varsayılan değer genellikle yeterince iyi olursa, yapardım. Ancak değilse, yapıcıdaki metnin istenmesi kullanıcıyı ne zaman olması gerektiğini düşünmeye zorlar.

Bu kullanıcıların aptal olmadığını unutmayın . Endişelenecek çok fazla gerçek sorunları var. Sınıfınızın "arayüzü" nü düşünerek, bunun gerçek bir problem ve gereksiz bir problem haline gelmesini de engelleyebilirsiniz.


0

Aşağıdaki önerilen çözümde, üst sınıf soyuttur ve üç üyenin de varsayılan bir değere ayarlanmış olması gerekir.

Alt sınıfın farklı kurucuları vardır, böylece programcı bunu başlatabilir.

İlk kurucu kullanılırsa, tüm üyelerin varsayılan değerleri olacaktır.

İkinci kurucu kullanılırsa, actionText üyesine diğer iki üyeyi varsayılan değerle bırakarak bir başlangıç ​​değeri verirsiniz ...

Üçüncü kurucu kullanılırsa, actionURext ve toolTip için yeni bir değerle başlatır ve imageURl'i varsayılan değerle bırakırsınız ...

Ve bunun gibi.

public abstract class Action {
    protected String text = "Default action text";
    protected String toolTip = "Default action tool tip";
    protected String imageURl = "http://myserver.com/images/default.png";

    .... rest of code, I guess setters and getters
}

public class MyAction extends Action {


    public MyAction() {

    }

    public MyAction(String actionText) {
        setText(actionText);
    }

    public MyAction(String actionText, String toolTip_) {
        setText(actionText);
        setToolTip(toolTip_);   
    }

    public MyAction(String actionText, String toolTip_; String imageURL_) {
        setText(actionText);
        setToolTip(toolTip_);
        setImageURL(imageURL_);
    }


}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.