Değerleri belirlemek için bir boolean parametresi kullanmak yanlış mı?


39

Göre bu davranışını belirlemek için bir boolean parametresini kullanmak yanlış mı? , Bir davranışı belirlemek için boolean parametreleri kullanmaktan kaçının önemini biliyorum, örneğin:

Orijinal versiyon

public void setState(boolean flag){
    if(flag){
        a();
    }else{
        b();
    }
    c();
}

Yeni sürüm:

public void setStateTrue(){
    a();
    c();
}

public void setStateFalse(){
    b();
    c();
}

Fakat boolean parametresinin davranışlar yerine değerleri belirlemek için kullanılması durumunda? Örneğin:

public void setHint(boolean isHintOn){
    this.layer1.visible=isHintOn;
    this.layer2.visible=!isHintOn;
    this.layer3.visible=isHintOn;
}

İsHintOn bayrağını kaldırmaya çalışıyorum ve 2 ayrı fonksiyon oluşturmaya çalışıyorum:

public void setHintOn(){
    this.layer1.visible=true;
    this.layer2.visible=false;
    this.layer3.visible=true;
}

public void setHintOff(){
    this.layer1.visible=false;
    this.layer2.visible=true;
    this.layer3.visible=false;
}

ancak değiştirilmiş sürüm daha az bakım gerektiriyor çünkü:

  1. Orijinal versiyondan daha fazla kod içeriyor

  2. katman 2'nin görünürlüğünün ipucu seçeneğinin zıttı olduğunu açıkça gösteremez.

  3. yeni bir katman (örneğin: layer4) eklendiğinde, eklemem gerekiyor

    this.layer4.visible=false;
    

    ve

    this.layer4.visible=true;  
    

    setHintOn () ve setHintOff () 'a ayrı ayrı

Öyleyse benim sorum, eğer boolean parametresi sadece değerleri belirlemek için kullanılıyorsa, fakat davranışlarda bulunmuyorsa (örneğin: bu parametrede başka bir if yoksa), hala bu boolean parametresini ortadan kaldırmak için tavsiye edilir mi?


26
Elde edilen kodun daha okunaklı ve bakımı kolay ise asla yanlış olmaz ;-) İki ayrı yöntem yerine tek bir yöntem kullanmanızı öneririm.
saat

32
Bu sınırlayıcıları ayarlayan bir yöntemin tek bir uygulamasının, sınıfın daha kolay bakımı ve uygulamasının anlaşılmasıyla sonuçlanacağı konusunda çarpıcı bir argüman sunuyorsunuz. Çok iyi; bunlar meşru düşünceler. Ancak, sınıfın kamusal arayüzünün onları barındıracak şekilde deforme olması gerekmez. Ayrı yöntemler, genel arayüzün anlaşılmasını ve üzerinde çalışmasını kolaylaştıracaksa, sizi özel bir yöntem setHint(boolean isHintOn)olarak tanımlayın ve sırasıyla ve ile çağıran genel ve ekleyin . setHintOnsetHintOffsetHint(true)setHint(false)
Mark Amery

9
Bu yöntem adlarından çok mutsuz olurdum: gerçekten herhangi bir fayda sağlamazlar setHint(true|false). Patates patates En azından setHintve gibi bir şey kullanın unsetHint.
Konrad Rudolph


4
@kevincline Durum bir ad ise, isen baştan yazarsınız . isValidpeki neden iki kelimeyle bunu değiştirdin? Ayrıca, "daha doğal" bakanın gözündedir. . Benim için daha sonra bir İngiliz cümle olarak telaffuz istiyorsanız bir "" sıkışmış ile "ipucu açıksa" olması daha doğal olurdu
Bay Lister

Yanıtlar:


95

API tasarımı, arayan bir taraftan , bir API müşterisi için en kullanışlı olana odaklanmalıdır .

Örneğin, bu yeni API arayanın böyle düzenli kod yazmasını gerektiriyorsa,

if(flag)
    foo.setStateTrue();
else
    foo.setStateFalse();

öyleyse, parametreden kaçınmanın, arayan kişinin yazmasına izin veren bir API'ye sahip olmasından daha kötü olduğu açık olmalıdır.

 foo.setState(flag);

Eski versiyon sadece o zaman arayan tarafında (ve muhtemelen bir kereden fazla) çözülmesi gereken bir sorun yaratır. Bu ne okunabilirliği ne de sürdürülebilirliği arttırmaz.

Ancak uygulama tarafı , genel API'nin nasıl göründüğünü belirlememelidir. setHintParametre gibi bir fonksiyonun uygulamada daha az kod gerektirmesi, ancak bir müşteri için kullanımı setHintOn/ terimleri açısından setHintOffdaha kolay görünen bir API olması durumunda , aşağıdaki şekilde uygulayabilirsiniz:

private void setHint(boolean isHintOn){
    this.layer1.visible=isHintOn;
    this.layer2.visible=!isHintOn;
    this.layer3.visible=isHintOn;
}

public void setHintOn(){
   setHint(true);
}

public void setHintOff(){
   setHint(false);
}

Bu nedenle, genel API'nin boolean parametresi olmamasına rağmen, burada yinelenen mantık yoktur, bu nedenle yeni bir gereksinim (soru örneğinde olduğu gibi) geldiğinde değiştirilecek tek yer vardır.

Bu aynı zamanda diğer yollarda da işe yarar setState: Yukarıdaki yöntemin iki farklı kod parçası arasında geçiş yapması gerekiyorsa, bu kod parçaları iki farklı özel yönteme yeniden yansıtılabilir. Yani IMHO, “bir parametre / bir yöntem” ile “sıfır parametreler / iki yöntem” arasında içsellere bakarak karar vermek için bir kriter aramak mantıklı değildir. Bununla birlikte, API'yi tüketici rolünde görmek istediğiniz şekilde bakın.

Şüpheniz varsa, sizi genel API ve bunun nasıl kullanılacağı hakkında düşünmeye zorlayacak "test odaklı geliştirme" (TDD) kullanmayı deneyin.


DocBrown, uygun bölme çizgisinin her bir durumun ayarlanmasının karmaşık ve muhtemelen geri dönüşü olmayan yan etkileri olup olmadığını mı söylersiniz? Örneğin, teneke üzerinde yazanları yapan bir bayrağı basitçe değiştiriyorsanız ve altta yatan bir devlet makinesi yoksa, farklı durumları parametrelendirirsiniz. Örneğin, SetLoanFacility(bool enabled)bir kredi sağladıktan sonra yeniden almak kolay olmayabilir ve iki seçenek tamamen farklı bir mantık içerebilir - ve ayırmak için hareket etmek isteyebilirsiniz. / Yöntemleri kaldır.
Steve

15
@Steve: Hala uygulama tarafında gördüğünüz gereksinimlerden API'yi tasarlamaya çalışıyorsunuz. Dürüst olmak gerekirse: bu tamamen alakasız. Ortak API’nin hangi değişkeninin kullanıldığını arayan tarafın kullanması daha kolaydır. Dahili olarak, iki genel yöntemin bir tanesini özel parametreli olarak çağırmasına izin verebilirsiniz. Ya da tam tersi, bir parametrenin bir yöntemle farklı mantıkla iki özel yöntem arasında geçiş yapmasını sağlayabilirsiniz.
Doktor Brown,

@Steve: düzenlememe bakın.
Doktor Brown,

Tüm puanlarınızı alıyorum - aslında arayanın tarafından düşünüyorum (bu nedenle "kalayda ne yazıyor" referansım) ve bir arayanın genellikle her yaklaşımı kullanmayı bekleyeceği uygun kuralı formüle etmeye çalışıyorum. Bana göre bu kural, arayan kişinin tekrar eden çağrıları kesin olarak beklememesi ve durum geçişlerinin sınırsız ve karmaşık yan etkileri olmadan beklemesini beklememesidir. Bir oda ışık anahtarını açıp kapatmak, bölgesel bir elektrik santralini açıp kapatmak çok yöntemli olacaktır.
Steve

1
@Steve Eğer kullanıcı belirli bir ayarı onaylamak isterse, o zaman Toggle()sağlamak için doğru işlev değildir. Bütün mesele bu; Arayan sadece “değiştir” ile ilgileniyorsa ve “neyin sonu” ile ilgilenmiyorsa Toggle(), ek kontrol ve karar vermekten kaçınan seçenektir. Bir COMMON davası demezdim, ne de iyi sebep olmadan kullanılabilir olmasını öneriyorum, ancak kullanıcı bir toggle'a ihtiyaç duyarsa o zaman bir toggle veririm.
Kamil Drakari

40

Martin Fowler, Kent Beck'ten ayrı setOn() setOff()yöntemler önermekten alıntı yapar ancak aynı zamanda bunun dokunulmaz olarak görülmemesi gerektiğini söyler:

Eğer böyle bir kullanıcı arayüzü denetimi veya veri kaynağı olarak bir boolean kaynağından [sic] veriyi, çekme, ben tercih ederdim setSwitch(aValue)daha

if (aValue)
  setOn();
else
  setOff();

Bu, arayanın işini kolaylaştıracak bir API'nin yazılması gerektiği bir örnektir, bu yüzden arayanın nereden geldiğini biliyorsanız, API'yi bu bilgiler göz önünde bulundurarak tasarlamalıyız. Bu ayrıca, arayanları her iki şekilde elde edersek, bazen her iki stili de sağlayabileceğimizi savunuyor.

Başka bir öneri , içeriğe özgü isimler vermek ve daha iyi hale getirmek için numaralandırılmış bir değer veya bayrak tipi kullanmaktır . Örnekte ve daha iyi olabilirdi.truefalseshowHinthideHint


16
Tecrübelerime göre, setSwitch (value) hemen hemen her zaman kesin olarak cevabınızda belirtilen if / else kodu nedeniyle setOn / setOff komutundan daha az genel kod oluşturur. SetSwitch (value) yerine bana setOn / setOff API'sini veren geliştiricilere küfür etme eğilimindeyim.
26

1
Buna benzer bir mercekten bakmak: Değerin ne olacağını kodlamanız gerekirse, bu ikisi için de kolaydır. Bununla birlikte, kullanıcı girişine ayarlamanız gerekiyorsa, değeri doğrudan girebiliyorsanız, bu bir adım kazandırır.
Nic Hartley

Somut bir karşı örnek olarak @ 17/26 (diğerine göre tercih edilmek yerine "buna bağlı olduğunu" göstermek için), Apple AppKit'te bir görünümün yeniden çizilmesi gerekip gerekmemesi durumunda -[NSView setNeedsDisplay:]geçeceğiniz bir yöntem vardır . Bunu asla yapmamasını söylemene gerek yok, bu yüzden UIKit'in parametresi yok. İlgili metoda sahip değil . YESNO-[UIView setNeedsDisplay]-setDoesNotNeedDisplay
Graham Lee,

2
@ GrahamLee, sanırım Fowler'in argümanı oldukça ince ve gerçekten yargılamaya dayanıyor. bool isPremiumÖrneğinde bir bayrak kullanmazdım , ancak BookingType bookingTypeher rezervasyon için mantık oldukça farklı olmadığı sürece, aynı yöntemi parametreleştirmek için bir enum ( ) kullanırdım. Fowler'ın ifade ettiği "karışık mantık", biri iki mod arasındaki farkın ne olduğunu görebilmek isterse, genellikle arzu edilir. Ve eğer kökten farklılarsa, parametrelenmiş yöntemi dıştan ortaya çıkarır ve ayrı yöntemleri içsel olarak uygulardım.
Steve

3

Bence yazınızda, API ve uygulamada iki şeyi karıştırdığınızı düşünüyorum. Her iki durumda da, her zaman kullanabileceğiniz güçlü bir kural olduğunu düşünmüyorum, ancak bu iki şeyi bağımsız olarak düşünmelisiniz (mümkün olduğunca).

Her ikisi de: API ile başlayalım:

public void setHint(boolean isHintOn)

ve:

public void setHintOn()
public void setHintOff()

Nesnenizin sunması gerekenlere ve müşterilerinizin API'yi nasıl kullanacaklarına bağlı olarak geçerli alternatiflerdir. Doc'un belirttiği gibi, kullanıcılarınız zaten bir Boolean değişkenine sahipse (bir UI kontrolünden, bir kullanıcı eyleminden, harici bir API'den, vb.), İlk seçenek daha mantıklı olur, aksi halde sadece müşterinin kodunda bir if if ifadesi zorlarsınız . Bununla birlikte, örneğin bir işleme başlarken ipucunu true olarak değiştiriyorsanız ve sonunda false yapıyorsanız, ilk seçenek size şöyle bir şey verir:

setHint(true)
// Do your process
…
setHint(false)

ikinci seçenek size şunu verir:

setHintOn()
// Do your process
…
setHintOff()

Hangi IMO çok daha okunaklı, bu durumda ikinci seçeneğe geçeceğim. Açıkçası, hiçbir şey sizi iki seçenek de önermekten alıkoyamaz (ya da daha fazlası, örneğin Graham’in dediği gibi enum kullanabilirsiniz).

Önemli olan, API'nızı, nesnenin ne yapması gerektiğine ve nasıl uygulayacağınıza bağlı olarak istemcilerin nasıl kullanacağına bağlı olarak seçmeniz gerektiğidir.

O zaman genel API'nizi nasıl uygulayacağınızı seçmelisiniz. Diyelim ki yöntemleri setHintOnve setHintOffgenel API'mız olarak seçtik ve bu ortak mantığı örneğinizdeki gibi paylaşıyorlar. Bu mantığı özel bir yöntemle (Doc'tan kopyalanan kod) kolayca soyutlayabilirsiniz:

private void setHint(boolean isHintOn){
    this.layer1.visible=isHintOn;
    this.layer2.visible=!isHintOn;
    this.layer3.visible=isHintOn;
}

public void setHintOn(){
   setHint(true);
}

public void setHintOff(){
   setHint(false);
}

Bunun tersine, setHint(boolean isHintOn)bir API seçtiğimizi varsayalım, ancak ipucunu Açık olarak ayarlamak nedenini Kapalı olarak ayarlamaktan tamamen farklı olduğu için örneğinizi tersine çevirelim. Bu durumda aşağıdaki gibi uygulayabiliriz:

public void setHint(boolean isHintOn){
    if(isHintOn){
        // Set it On
    } else {
        // Set it Off
    }    
}

Ya da:

public void setHint(boolean isHintOn){    
    if(isHintOn){
        setHintOn()
    } else {
        setHintOff()
   }    
}

private void setHintOn(){
   // Set it On
}

private void setHintOff(){
   // Set it Off 
}

Mesele şu ki, her iki durumda da, önce genel API'mızı seçtik ve daha sonra uygulamalarımızı seçilen API'ye (ve sahip olduğumuz kısıtlamalara) uygun şekilde uyarladık.

Bu arada, aynısının davranışı belirlemek için bir boolean parametresi kullanma hakkında bağladığınız gönderi için de geçerli olduğunu düşünüyorum, yani bazı zor kurallardan ziyade belirli kullanım durumunuza dayanarak karar vermelisiniz (ancak bu durumda genellikle yapılacak doğru şey Birden çok işlevde onu kırmak).


3
Bir yan not olarak, sözde blok gibi bir şey varsa (başında bir ifade, sonunda bir tane), muhtemelen ne yaptığını açıkça belirtmek için kullanmanız beginve / endveya eşanlamlıları kullanmanız gerekir. başlangıcın bir sonu olmalı ve bunun tersi de geçerlidir.
Nic Hartley,

Nic ile aynı fikirdeyim ve şunu ekleyeceğim: Başlangıçların ve sonların her zaman birleştiğinden emin olmak istiyorsanız, bunun için dile özgü deyimler de sağlamanız gerekir: C ++ 'da RAII / kapsam korumaları, usingC #' da bloklar with, Python'daki ifade bağlam yöneticileri, Bir lambda veya çağrılabilir nesne (örneğin, Ruby blok sözdizimi) vb.
Daniel Pryden,

Her iki nokta ile aynı fikirdeyim, sadece diğer durumu açıklamak için basit bir örnek vermeye çalışıyordum (her ikinizin de belirtmiş olduğunuz gibi kötü bir örnek olsa da :)).
jesm00

2

İlk önce ilk şeyler: kod biraz daha uzun olduğu için otomatik olarak daha az bakım gerektirmez. Netlik önemli olan şeydir.

Şimdi, gerçekten sadece verilerle ilgileniyorsanız, sahip olduğunuz şey bir boolean özelliği için belirleyicidir. Bu durumda, doğrudan bu değeri doğrudan depolamak ve katman görünürlüklerini elde etmek isteyebilirsiniz.

bool isBackgroundVisible() {
    return isHintVisible;
}    

bool isContentVisible() {
    return !isHintVisible;
}

(Katmanlara gerçek isimler verme özgürlüğünü aldım - eğer orijinal kodunuzda yoksa, onunla başlardım)

Bu hala bir setHintVisibility(bool)yönteme sahip olup olmadığı sorusu ile size bırakır . Şahsen, onu showHint()ve hideHint()yöntemiyle değiştirmenizi tavsiye ederim - her ikisi de gerçekten basit olacak ve katman eklediğinizde bunları değiştirmek zorunda kalmayacaksınız. Ancak bu kesin olarak doğru / yanlış değil.

Şimdi eğer işlev çağırmak aslında bu katmanların görünürlüğünü değiştirmeli ise, aslında davranışınız var. Bu durumda kesinlikle ayrı yöntemler önerebilirim.


Öyleyse tl; dr: İki işleve ayrılmanızı öneririz, çünkü katmanları eklerken bunları değiştirmek zorunda kalmayacaksınız? Bir layer4 eklenirse, "this.layer4.visibility = isHintOn" dememiz gerekebilir, bu yüzden aynı fikirde olduğumdan emin değilim. Eğer bir şey varsa, bu ona karşı bir hakaret, bir katman eklendiğinde olduğu gibi iki fonksiyonu düzenlemek zorundayız, sadece bir tane değil.
Erdrik Ironrose,

Hayır, ben (zayıf) netlik için tavsiye ederim ( showHintvs setHintVisibility). OP'den endişelendiği için yeni katmandan bahsettim. Ayrıca, sadece bir yeni yöntemi eklemek gerekir: isLayer4Visible. showHintve hideHintsadece isHintVisibleniteliği true / false olarak ayarlayın ve bu değişmez.
Doubleyou

1
@doubleYou, daha uzun kodun otomatik olarak daha az bakım gerektirmediğini söylüyorsunuz. Kod uzunluğunun, yalnızca yapısal karmaşıklıkla üst üste gelen, bakım ve netlikte temel değişkenlerden biri olduğunu söyleyebilirim . Yapısal olarak daha karmaşık ve daha karmaşık hale gelen herhangi bir kod, bunu hak etmelidir, aksi takdirde basit sorunlar, kodda hak ettiklerinden daha karmaşık bir işlem görür ve kod temeli, gereksiz satırların çalılıklarını alır ("çok fazla dolaylı düzey" sorunu).
Steve

@Steve Bir şeyleri fazladan yapabileceğinize, yani kodu daha açık hale getirmeden daha uzun hale getireceğinize tamamen katılıyorum - otoh, her zaman netlik pahasına kod kısaltabilirsiniz, bu nedenle burada 1: 1 ilişki yoktur.
saat

Böyle bir kod alıp çok hatlarında onu yeniden yazmayı - “kod golf” Think @Steve gelmez genellikle net hale getirir. “Kod golfü” aşırı bir şey ama her şeyi tek bir zekice ifadeye sokmanın “şık” ve belki de daha hızlı olduğunu düşünen birçok programcı var çünkü derleyiciler yeterince iyi bir optimizasyon yapmıyor.
BlackJack

1

İkinci örnekte Boole parametreleri iyi. Zaten anladığınız gibi, boole parametreleri kendi başlarına problemli değildir. Sorunlu olan bir bayrağa dayanan davranışını değiştiriyor.

İlk örnek problemlidir, çünkü adlandırma bir belirleyici yöntemi gösterir, ancak uygulamalar farklı bir şey gibi görünmektedir. Yani davranış değiştirme antipattern ve yanıltıcı olarak adlandırılmış bir yöntem var. Fakat eğer yöntem aslında normal bir belirleyici ise (davranış değiştirme olmadan), o zaman sorun olmaz setState(boolean). İki yönteme sahip olmak setStateTrue()ve setStateFalse()faydası olmadan gereksiz yere işleri karmaşıklaştırmaktır.


1

Bu sorunu çözmenin bir başka yolu, her ipucunu temsil edecek bir nesne sunmak ve bu ipucu ile ilişkili boolean değerlerini belirlemekten nesnenin sorumlu olmasını sağlamaktır. Bu şekilde, sadece iki boolean duruma sahip olmak yerine, yeni permütasyonlar ekleyebilirsiniz.

Örneğin, Java’da şunları yapabilirsiniz:

public enum HintState {
    SHOW_HINT(true, false, true),
    HIDE_HINT(false, true, false);

    private HintState(boolean layer1Visible, boolean layer2Visible, boolean layer3Visible) {
         // constructor body and accessors omitted for clarity
    }
}

Ve sonra arayan kodunuz şöyle görünür:

setHint(HintState.SHOW_HINT);

Uygulama kodunuz şöyle görünür:

public void setHint(HintState hint) {
    this.layer1Visible = hint.isLayer1Visible();
    this.layer2Visible = hint.isLayer2Visible();
    this.layer3Visible = hint.isLayer3Visible();
}

Bu, uygulama kodunu ve arayan kodunu özlü bir şekilde tutar, açıkça yazılan, belirtilen durum kümelerine yönelik niyetleri açıkça tanımlayan yeni bir veri türünü tanımlamak yerine . Bence bu her yerde daha iyi.


0

Öyleyse benim sorum, eğer boolean parametresi sadece değerleri belirlemek için kullanılıyorsa, fakat davranışlarda bulunmuyorsa (örneğin: bu parametrede başka bir if yoksa), hala bu boolean parametresini ortadan kaldırmak için tavsiye edilir mi?

Böyle şeyler hakkında şüphelerim olduğunda. Yığın izinin nasıl göründüğünü hayal etmeyi seviyorum.

Uzun yıllar boyunca setter ve getter ile aynı işlevi kullanan bir PHP projesi üzerinde çalıştım . Eğer boş atarsanız , değeri döndürür, aksi takdirde ayarlayın. Çalışmak korkunçtu .

İşte bir yığın iz örneği:

function visible() : line 440
function parent() : line 398
function mode() : line 384
function run() : line 5

İç durum hakkında hiçbir fikriniz yoktu ve hata ayıklamayı zorlaştırıyordu. Başka olumsuz yan etkileri de var, ancak işlevler tek bir işlem gerçekleştirdiğinde ayrıntılı işlev adında ve netlikte bir değer olduğunu görmeye çalışın .

Şimdi bir boolean değerine dayalı A veya B davranışı olan bir işlev için yığın iziyle çalışan resmi.

function bar() : line 92
function setVisible() : line 120
function foo() : line 492
function setVisible() : line 120
function run() : line 5

Bana sorarsan bu kafa karıştırıcı. Aynı setVisibleçizgiler iki farklı iz yolu sağlar.

Öyleyse sorunuza geri dönün. Yığın izlemesinin nasıl görüneceğini, bir kişiye ne olduğunu nasıl ilettiğini ve kodun hatalarını ayıklamak için gelecekteki bir kişiye yardım edip etmediğinizi kendinize sorun.

İşte bazı ipuçları:

  • Argüman değerlerini bilmeye ihtiyaç duymadan niyeti ima eden açık bir fonksiyon ismi.
  • bir işlev tek bir işlem gerçekleştirir
  • isim mutasyon veya değişmez davranış anlamına gelir
  • dilin ve araçların hata ayıklama becerisine göre hata ayıklama sorunlarını çözebilir.

Bazen kod mikroskop altında aşırı görünür, ancak daha büyük resme geri döndüğünüzde minimalist bir yaklaşım onu ​​ortadan kaldırır. Eğer öne çıkması için ihtiyacınız varsa, onu koruyabilirsiniz. Birçok küçük işlev eklemek aşırı derecede ayrıntılı olabilir, ancak daha geniş bir bağlamda geniş bir şekilde kullanıldığında bakımı geliştirir.


1
setVisibleYığın izi konusunda kafamı karıştıran şey, setVisible(true)aramanın setVisible(false)(veya bu izin nasıl gerçekleştiğine bağlı olarak başka bir yolla) yapılan bir çağrıya yol açması şeklinde görünmesidir .
David K

0

Bir şeyin davranışını değiştirmek için bir booleanparametreyi bayrak olarak bir yönteme geçirdiğiniz hemen her durumda , bunu yapmanın daha açık ve daha güvenli bir yolunu düşünmelisiniz .

Eğer bir Enumdurumu kullanmaktan başka bir şey yapmazsanız , kodunuzu daha iyi anladınız.

Bu örnek aşağıdakilerden Nodesınıfı kullanır JavaFX:

public enum Visiblity
{
    SHOW, HIDE

    public boolean toggleVisibility(@Nonnull final Node node) {
        node.setVisible(!node.isVisible());
    }
}

her zaman, birçok JavaFXnesnede bulunandan daha iyidir :

public void setVisiblity(final boolean flag);

ama sanırım .setVisible()ve .setHidden()durum için en iyi çözümdür bayrak bir olduğunu booleano azından ayrıntılı en açık ve olduğu gibi.

Birden fazla seçime sahip bir şey söz konusu olduğunda, bu şekilde yapılması daha da önemlidir. EnumSetsadece bu nedenle var.

Ed Mann'in bu konuda çok iyi bir blog yazısı var. Söylediklerinin aynısını yapmak üzereydim, bu yüzden çabayı çoğaltmak için değil, sadece bu cevabın eki olarak blog postasına bir link göndereceğim .


0

Bir (boolean) parametreye karşılık bazı parametrelere dayanan aşırı yüklü yöntemlere karşı geçen bazı arabirimler için bir yaklaşım arasında karar verirken, tüketen müşterilere bakın.

Tüm kullanımların sabit değerler (örneğin doğru, yanlış) geçmesi durumunda, bu aşırı yükleri savunur.

Tüm kullanımların değişken bir değeri geçmesi durumunda, bu parametre yaklaşımlı yönteme yöneliktir.

Bu aşırı uçların hiçbiri geçerli değilse, bu, müşteri kullanımlarının bir karışımı olduğu anlamına gelir; bu nedenle, her iki formu da destekleyip desteklememeyi seçmeniz veya bir müşteri kategorisini diğerine adapte etmek için (ne onlar için doğal değildir) seçmelisiniz.


Ne eğer entegre bir sistem tasarlarken ve vardır sonuçta kod üreticisi ve kod "tüketen müşteri" hem? Tüketici bir müşterinin ayakkabısında duran bir kişi bir yaklaşım yerine yönelik tercihini nasıl oluşturmalıdır?
Steve

@Steve, Tüketici müşteri olarak, sabit veya değişken geçirip geçirmediğinizi bilirsiniz. Sabitleri geçiyorsa, parametre olmadan aşırı yükleri tercih edin.
Erik Eidt,

Ama neden böyle olması gerektiğini açıkça ifade etmekle ilgileniyorum. Neden sınırlı sayıda sabit değer için kaynak kullanmıyorsunuz, çünkü çoğu dilde tam olarak bu amaç için tasarlanmış hafif bir sözdizimi budur?
Steve

@Steve, tasarım zamanında / derleme zamanında müşterilerin her durumda sabit bir değer (doğru / yanlış) kullanacağını biliyorsak, o zaman bu, bir genelleştirilmiş yöntemden (bir parametre alan) ziyade gerçekten iki farklı özel yöntem olduğunu göstermektedir. Kullanılmadığında parametreli bir yöntemin genelliğini tanıtmaya karşı çıkarım - bu bir YAGNI argümanıdır.
Erik Eidt

0

Tasarım için iki husus var:

  • API: Kullanıcıya hangi arayüzü sunduğunuz,
  • Uygulama: netlik, bakım kolaylığı, vb ...

Onlar birbirine karışmamalı.

Bu tamamen iyidir:

  • API yetkilendirmesinde tek bir uygulamaya devredilecek birden fazla metoda sahip olmak,
  • API gönderiminde duruma bağlı olarak birden fazla uygulamaya tek bir yöntem var.

Bu nedenle, bir API tasarımının maliyet / faydalarını uygulama tasarımının maliyet / faydaları ile dengelemeye çalışan herhangi bir tartışma şüphelidir ve dikkatlice incelenmelidir.


API tarafında

Bir programcı olarak, genellikle programlanabilir API'leri tercih edeceğim. Bir işlevi iletebileceğimde, hangi işlevi arayacağınıza karar vermek için değere ilişkin bir if/ switchifadesine ihtiyacım olandan çok daha açık bir kod var .

Her işlev farklı argümanlar beklerse, ikincisi gerekli olabilir.

Senin durumunda, tek bir yöntem setState(type value)daha iyi görünüyor.

Ancak , isimsiz daha kötü bir şey yoktur true, false, 2, vb ... bu sihirli değerleri kendi başlarına hiçbir anlamı yoktur. İlkel takıntılardan kaçının ve güçlü yazmayı benimseyin.

Böylece, bir API POV, ben istiyorum: setState(State state).


Uygulama tarafında

Daha kolay olanı yapmanı öneririm.

Yöntem basitse, en iyi şekilde bir arada tutulur. Kontrol akışı kıvrılırsa, her biri bir alt kasa veya boru hattının bir adımıyla ilgili olan birden fazla yöntemde ayrılması en iyisidir.


Son olarak, gruplamayı düşünün .

Örneğinizde (okunabilirlik için boşluk bırakıldı):

this.layer1.visible = isHintOn;
this.layer2.visible = ! isHintOn;
this.layer3.visible = isHintOn;

Neden layer2trendi dalgalandırıyor? Bu bir özellik mi yoksa bir böcek mi?

O 2 listesine sahip olmak mümkündür olabilir [layer1, layer3]ve [layer2]bir ile açık onlar gruplanmış nedeni belirtilmek isim ve sonra bu listeleri üzerinde yineleme.

Örneğin:

for (auto layer : this.mainLayers) { // layer2
    layer.visible = ! isHintOn;
}
for (auto layer : this.hintLayers) { // layer1 and layer3
    layer.visible = isHintOn;
}

Kod kendisi için konuşur, neden iki grubun olduğu ve davranışlarının farklılık gösterdiği açıktır .


0

setOn() + setOff()Vs set(flag)sorusundan ayrı olarak, bir boole türünün burada en iyi olup olmadığını dikkatlice düşünürdüm. Asla üçüncü bir seçenek olmayacağından emin misin?

Bir boole yerine bir enum düşünmeye değer olabilir. Genişletilebilirliğe izin vermenin yanı sıra, bu aynı zamanda boolinin yanlış şekilde yükseltilmesini de zorlaştırır, örneğin:

setHint(false)

vs

setHint(Visibility::HIDE)

Enum ile, birisi 'gerektiğinde' seçeneği istediğine karar verdiğinde uzatılması daha kolay olacaktır:

enum class Visibility {
  SHOW,
  HIDE,
  IF_NEEDED // New
}

vs

setHint(false)
setHint(true)
setHintAutomaticMode(true) // New

0

... 'a göre davranışları belirlemek için boolean parametreleri kullanmaktan kaçınmanın önemini biliyorum

Bu bilgiyi tekrar değerlendirmeyi öneriyorum.

Öncelikle, bağladığınız SE sorusunda önerdiğiniz sonucunu görmüyorum. Çoğunlukla, bir zincirin çok aşağısında değerlendirildiği birkaç yöntem çağrısı adımında bir parametre iletmekten bahsediyorlar.

Örneğinizde, metodunuzdaki parametreyi doğru değerlendiriyorsunuz. Bu bakımdan, diğer herhangi bir parametreden hiçbir şekilde farklı değildir.

Genel olarak, boole parametrelerinin kullanılmasında kesinlikle hiçbir yanlışlık yoktur; ve açıkçası herhangi bir parametre bir davranışı belirleyecektir, ya da niçin ilk etapta buna sahiptiniz?


0

Soruyu tanımlamak

Başlık sorunuz "Yanlış mı [...]?" Mı? - ama "yanlış" ile ne demek istiyorsun?

Bir C # veya Java derleyicisine göre, yanlış değil. Bunun farkında olduğun konusunda eminim ve istediğin şey bu değil. Bundan başka korkuyorum, sadece nprogramcılarımızın n+1farklı görüşleri var. Bu cevap, Temiz Kod kitabının bu konuda ne söyleyeceğini sunar.

Cevap

Temiz Kod , genel olarak işlev bağımsız değişkenlerine karşı güçlü bir durum oluşturur:

Argümanlar zor. Çok fazla kavramsal güç alıyorlar. [...] okuyucularımız her gördüklerinde yorumlamak zorunda kalacaklardı.

Buradaki bir "okuyucu", API tüketicisi olabilir. Ayrıca, bu kodun henüz ne yaptığını bilmeyen bir sonraki kodlayıcı olabilir - bu bir ay içinde siz olabilirsiniz. Ya iki işlevi ayrı ayrı ya da bir kez iki kez , bir truekez falseakılda tutarak bir kez işlevden geçer .
Kısacası, mümkün olduğunca az argüman kullanın .

Bir bayrak argümanının özel durumu daha sonra doğrudan ele alınır:

Bayrak argümanları çirkin. Bir boole fonksiyona geçmek gerçekten korkunç bir uygulamadır. Derhal yöntemin imzasını zorlaştırır, bu fonksiyonun birden fazla şey yaptığını yüksek sesle ilan eder. Bayrak doğru ise bir şey, bayrak yanlış ise bir şey yapar!

Sorularınızı doğrudan cevaplamak için:
Temiz Kod'a göre , bu parametreyi ortadan kaldırmanız önerilir.


İlave bilgi:

Örneğiniz oldukça basittir, ancak orada bile kodunuza yayılan basitliği görebilirsiniz: Parametre içermeyen işlevler yalnızca basit atamalar yapar, diğer işlev aynı hedefe ulaşmak için boole aritmetiği yapmalıdır. Bu basitleştirilmiş örnekte önemsiz bir boole aritmetiğidir, ancak gerçek bir durumda oldukça karmaşık olabilir.


API kullanıcısına bağımlı hale getirmeniz gerektiğine dair birçok tartışma gördüm, çünkü bunu bir çok yerde yapmak aptalca olurdu:

if (isAfterSunset) light.TurnOn();
else light.TurnOff();

Ben do bir şeylerin olmayan optimum burada oluyor katılıyorum. Belki de görmek çok açık, ama ilk cümleniz "davranış belirtmek için boolean parametreleri kullanmaktan kaçınmanın öneminden" bahsediyor ve bu tüm sorunun temelini oluşturuyor. API kullanıcısı için daha kolay yapılması gereken bu şeyi yapmak için bir neden görmüyorum.


Test yapıp yapmadığınızı bilmiyorum - bu durumda, şunu da göz önünde bulundurun:

Bağımsız değişkenler, test açısından bile daha zordur. Tüm çeşitli argüman kombinasyonlarının düzgün çalıştığından emin olmak için tüm test senaryolarını yazmanın zorluğunu hayal edin. Eğer argüman yoksa, bu önemsizdir.


Lede'yi gerçekten buraya gömdün: "... ilk cümlede" bir davranışı belirlemek için boolean parametrelerini kullanmaktan kaçınmanın önemi "den bahsediyor ve bu tüm sorunun temelini oluşturuyor. API kullanıcısı için daha kolay yapılması gereken bu şeyi yapmak için bir neden. " Bu ilginç bir nokta, ancak son paragrafınızda kendi argümanınızı baltalamayı tercih ediyorsunuz.
Wildcard,

Lede gömülü? Bu cevabın özü, bu cevabın ilk yarısında açıklanan "mümkün olduğunca az argüman kullanmak" dır. Bundan sonraki her şey sadece ek bilgidir: çelişkili bir argümanı (OP değil başka bir kullanıcı tarafından) ve herkese uygulanmayan bir şeyi reddetmek.
R. Schmitz

Son paragraf sadece başlık sorusunun cevaplanacak kadar iyi tanımlanmadığını açıkça ortaya koymaya çalışıyor. OP “yanlış” olup olmadığını soruyor ancak kime veya neye göre olduğunu söylemiyor. Derleyiciye göre mi? Geçerli kod gibi görünüyor, bu yüzden yanlış değil. Kitaba göre Temiz Kod? Bir bayrak argümanı kullanır, yani evet "yanlıştır". Bununla birlikte, pragmatik> dogmatik olduğundan, bunun yerine "önerilir" yazarım. Bunu daha netleştirmem gerektiğini mi düşünüyorsun?
R. Schmitz

bu yüzden bekleyin, cevabınızı savunmanız, başlık sorusunun cevaplanamayacak kadar açık olmaması mı? : D Tamam ... Aslında alıntı yaptığım şeyin ilginç ve ilginç bir fikir olduğunu düşündüm.
Joker,

1
Şimdi açıkça temizleyin; aferin!
Joker
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.