È meglio Show () + Hide () o SetVisible (bool visibile)?


59

Cosa è meglio e perché? (Dal punto di vista dell'interfaccia):

a) Avere due Show()e Hide()funzioni

b) Avere una SetVisible(bool visible)funzione

EDIT: Ad esempio alcuni oggetti hanno uno stato di visibilità e questa funzione viene utilizzata per cambiarlo.

c) Per avere tutti e tre Show(), Hide(), SetVisible(bool visible)funzioni


4
In quale contesto? Generalmente non importa
Aviv Cohn,


6
Perché non averli tutti pubblici? Ci sono casi in cui sai che verranno sempre mostrati o nascosti e ci sono casi in cui vorresti mostrare o nascondere in modo condizionale.
Pllee

@pllee: questo è probabilmente un ottimo punto.
user3123061

4
In Java, sarebbe setVisible, hide e show senza la lettera maiuscola iniziale.
Pierre Arlaud,

Risposte:


81

Preferisco SetVisible(bool visible), perché mi permette di scrivere il codice client in questo modo:

SetVisible(DetermineIfItShouldBeVisible());

invece di dover scrivere

if (DetermineIfItShouldBeVisible()) {
    Show();
} else {
    Hide();
}

L' SetVisibleapproccio può anche consentire una più facile implementazione. Ad esempio, se una determinata classe concreta delega semplicemente il metodo alle sue classi composte, SetVisiblesignifica implementare un metodo in meno.

void ButtonWithALabel::SetVisible(bool visible) {
    myButton.SetVisible(visible);
    myLabel.SetVisible(visible);
}

25
Allo stesso modo, potresti anche rendere Visible una proprietà, supponendo che la tua lingua lo supporti. MyObject.Visible = false;mi sembra ancora più intuitivo diMyObject.SetVisible(false);
Brian

9
@Brian Per me è meno leggibile e debuggable, perché nasconde il comportamento del programma ai miei occhi - la chiamata del metodo sottostante - ma questa è un'altra storia. Java non supporta questa sintassi, comunque è una questione di preferenze e allenamento degli occhi.
ignis,

10
SetVisible()non suggerisce (per me) che in realtà stai mostrando qualcosa. Sembra più come se stessi impostando la proprietà di visibilità di un oggetto, possibilmente lasciandolo su un corrispondente Refresh()o Redisplay()metodo per verificare il valore di questa proprietà per determinare se l'oggetto deve essere visualizzato o nascosto.
TMN

1
Sfortunatamente Java non supporta proprietà come C #, ma solo getter e setter che vedi sopra.
theGreenCabbage

1
@TMN: mi aspetterei che in assenza di altri fattori che impediscono la visibilità (ordine Z, visibilità principale, posizione, ecc.) Metterebbe setVisible(true)in moto un processo in cui l'oggetto verrebbe disegnato quando il sistema era al minimo successivo, se non prima. Mi aspetterei che ciò refreshpossa essere utile per accelerare la visualizzazione dell'oggetto, ma che l'oggetto alla fine verrebbe disegnato indipendentemente (a meno che, ad esempio, la sua visibilità non sia stata impostata falseprima che si verificasse).
supercat

35

Non sono d'accordo con tutti i poster che suggeriscono che più funzioni per fare la stessa cosa siano buone. Mentre tre funzioni invece di uno non possono sembrare molto gonfiare, ricordate che la vostra classe rischia di finire con molte di queste funzioni (ad esempio setEnabled, enable, disable) e quindi questo approccio si concluderà con un molto più interfaccia di classe più grande. Inoltre, è probabile che finirai con un mucchio di funzioni / proprietà / proprietà / suoni simili nella tua classe e la moltiplicazione delle funzioni oscurerà ulteriormente quale si accompagna a cosa.

Nei linguaggi che supportano le proprietà, questi dovrebbero essere preferiti, ma dal momento che né Java né C ++ lo fanno, immagino che sia un punto controverso.

Penso che setVisible()dovrebbe essere preferito per questi motivi:

  1. È immediatamente ovvio quale sia la funzione inversa. Per invertire la setVisible(false)chiamata, setVisible(true)mentre l'opposto di hide()potrebbe essere facilmente reveal().
  2. È programmaticamente più semplice ogni volta che si determina lo stato che deve assumere nel codice, ovvero è possibile chiamare setVisible(wantToSee)anziché utilizzare ifun'istruzione.
  3. Una volta che hai più funzioni simili, il setX()formato si generalizza in modo da poter avere una serie di funzioni coerenti mentre l'approccio verbale genera una serie di funzioni che possono essere difficili da individuare se non sai cosa stai cercando. La coerenza nelle API le rende notevolmente più facili da imparare e ricordare.

3
Il C ++ non ha proprietà, ma ha funzioni gratuite, quindi puoi estendere l'interfaccia di classe senza aggiungere nuove funzioni membro, cioè con un grado di accoppiamento inferiore.
galleria

Qt fornisce spesso tutte e tre le comodità in modo che hide () e show () possano essere collegati direttamente ad altri eventi usando il sistema di segnale / slot. Questo è in realtà un limite del sistema di slot - se stesse usando qualcosa di più simile a boost :: funzioni, l'argomento vero / falso potrebbe essere associato al punto di impostare il callback.

1
"Nei linguaggi che supportano le proprietà, questi dovrebbero essere preferiti, ma dato che né Java né C ++ lo fanno, immagino che sia un punto controverso." non necessariamente. Preferisce getter / setter? Sì. Ma set_visible non è in realtà un setter.
Miles Rout,

19

Dipende da cosa significa mostrare e nascondere nel contesto. Prima di tutto devi capire qual è il tuo "modo principale" e concentrarti sullo sviluppo di questo:

  • Motivi per scegliere setVisible(bool)
    • È solo un semplice capovolgimento, o il tuo oggetto ha principalmente lo stato di conservazione
    • Il tuo oggetto trascorrerà la maggior parte del suo tempo in un framework CRUD
    • C'è molto codice facilmente condivisibile tra mostrare e nascondere
  • Ragioni per scegliere show()ehide()
    • Esistono importanti effetti collaterali o molta logica in esecuzione, ad esempio quando l'oggetto deve controllare tutti i suoi contenitori per il loro stato di visibilità o innesca un'animazione di transizione.
    • Fa parte di un modello di dominio in cui è importante esprimere l' intenzione

OK, quindi ora che hai codificato il suo nucleo "gold standard", devi capire se vale la pena aggiungere sottili metodi di convenienza nell'altro stile, per rendere la vita più facile a chiunque userà il tuo oggetto.

  • Convenienza di setVisible(bool)
    • Ti consente di evitare dichiarazioni if ​​che hanno condizioni insignificanti e influiscono solo sulla visibilità (es. setVisible(a==b))
    • Può essere cablato in determinati framework getter / setter, se è qualcosa che ti aspetti che accada
  • Convenienza di show()ehide()
    • Utile in una lingua con funzioni e callback di prima classe (es. onSuccess(widget.show))
    • Molto più facile da leggere con le tracce dello stack e la profilazione delle prestazioni, poiché puoi vedere rapidamente cosa stava cercando di fare il programma

TLDR: scopri qual è il più importante, implementalo e poi chiediti se vale la pena aggiungere l'altro stile come metodi di convenienza.


11

Direi "tutti e tre".

Show()e Hide()tendono ad essere più facili da grok di SetVisible(true)e SetVisible(false). Tuttavia, quando si desidera impostare la visibilità logicamente, è meglio avere un metodo che prenda un metodo boolpiuttosto che costruirlo ifattorno bool.

Puoi supportare tutti e tre senza duplicare la logica e il minimo boilerplate:

void Show() {
    foo.Show();
    bar.Show();
}

void Hide() {
    foo.Hide();
    bar.Hide();
}

void SetVisible(bool visible) {
    if (visible) {
        Show();
    } else {
        Hide();
    }
}

In alternativa, se le cose che stai avvolgendo hanno SetVisibleun'API più -ish:

void Show() {
    SetVisible(true);
}

void Hide() {
    SetVisible(false);
}

void SetVisible(bool visible) {
    foo.SetVisible(visible);
    bar.SetVisible(visible);
}

40
Microsoft utilizza questo approccio per l'avvio e l'arresto System.Windows.Forms.Timer. Personalmente, trovo che questo sia fonte di confusione. Quando vedo entrambi Showe SetVisible, la mia prima inclinazione è chiedermi se ci sia qualche differenza importante tra le due funzioni.
Brian,

1
Puoi facilmente documentarli per eliminare quella confusione. Non ho fatto questo come un semplice esempio.
Garry Shutler,

20
Quindi ora devo dedicare X minuti extra a leggere la documentazione prima di sentirmi a mio agio con la lezione? Oppure, in alternativa, devo perdere X minuti extra di tempo per essere confuso (o introdurre bug)? Certo, X è piuttosto piccolo per questo tipo di cose, ma sicuramente non è zero. Offrire tutte e 3 le opzioni significa offrire il triplo delle funzioni necessarie, il che significa che spendi più lavoro a documentare e io spendo più lavoro a imparare come usare la classe. Inoltre, introduce un altro modo per i diversi sviluppatori di essere incoerenti durante l'utilizzo della classe.
Brian,

5
Questa è una chiara violazione del principio Interface Segregation, uno dei principi SOLID. Un'altra opinione contro il tuo approccio è quella di Jaroslav Tulach, designer di netbeans, che insiste molte volte nel fornire un solo modo per fare una cosa all'interno di un'API nel suo libro API design pratico.
AlfredoCasado,

@AlfredoCasado Sono d'accordo. E se SetVisible fosse protetto comunque? È possibile accedervi da una sottoclasse, ma la chiamata a una determinata entità con questa interfaccia (come un'API) dovrebbe essere Nascondi / Mostra.
Pierre Arlaud,

5

Preferisco show () e hide (), infatti, ogni metodo che riceve un booleano può essere modificato per due metodi tan che esprimono meglio l'intenzione dell'API. Ad esempio Robert Martin in codice pulito consiglia di preferire metodi con argomenti zero rispetto ai metodi con un argomento.

Un altro argomento importante per me è la leggibilità, secondo me il buon codice può essere letto come la prosa, la sua prosa davvero strana è qualcosa come "main_window setVisible false" invece di "main_window hide", scrivi o parli normalmente?, Perché usare questo strano costruzione del linguaggio nei programmi software quando è perfettamente possibile usare un linguaggio più naturale ?.


1
L'assemblatore non è abbastanza in prosa?
Alexander

Mi aspetto che la sequenza it.setVisible(false); it.setVisible(true);non dovrebbe influenzare la visibilità del genitore di un controllo, né dovrebbe influenzare l'ordine Z o la posizione del controllo. Al contrario hide(); show(),; potrebbe piuttosto plausibilmente forzare la visibilità del genitore di un controllo, spostarlo al di sopra di altri controlli e limitarne la posizione in un punto che può essere visto. In alcuni casi, è utile disporre di un mezzo per assicurarsi che qualcosa sia effettivamente visibile (come show()nel caso di cui sopra , ma in altri casi è utile cambiare il flag di visibilità senza cambiare nient'altro.
supercat

In un'API orientata agli oggetti non ci sono "flag", OO riguarda la messaggistica, si tratta di dire ad altri oggetti di svolgere alcune attività, non di cambiare "flag" che sono lo stato dell'oggetto. Stai facendo molte ipotesi su controllo, genitori, ordinamento z e le cose che ti aspetti basandosi probabilmente sulla tua precedente esperienza con altre API, è una pessima idea progettare un'API basata su sentimenti personali e ipotesi su un dominio.
AlfredoCasado,

5

Credo che più il metodo è espressivo, più leggibile e, di conseguenza, mantenibile il codice sarà. Considera i seguenti due casi:

Caso 1:

void showCustomerData(customerId){
  Customer customer = getCustomer(CustomerId);
  customerPanel.setVisible(customer.isCustomerEnabled());
}

Caso 2:

void showCustomerData(customerId){
  Customer customer = getCustomer(CustomerId);
  //always show customer panel
  customerPanel.setVisible(true);
}

Nel primo caso, è chiaro cosa sta facendo la funzione "setVisible", ma se vuoi leggerlo, dovresti dire:

impostare il pannello del cliente su visibile se il cliente è abilitato o impostarlo su nascosto se il cliente è disabilitato.

Mentre è più descrittivo dire:

  • controllare lo stato del cliente:
    • se il cliente è abilitato, mostra il pannello del cliente
    • altrimenti, nascondilo

che cambierà la funzione "Caso 1" nel modo seguente:

void showCustomerData(customerId){
  Customer customer = getCustomer(CustomerId);
  if(customer.isCustomerEnabled()){
    customerPanel.Show();
  }
  else{
    customerPanel.Hide();
  }
}

produce più codice, ma è più leggibile.

Il secondo caso ha un difetto evidente, ovvero sai già che vuoi mostrare il pannello, quindi perché non usare la funzione "Mostra"?

Non sto dicendo che usare "setVisible" sia assolutamente sbagliato, ma diventa confuso quando provi a leggere il codice non scritto da te nel tempo, e non è conforme alla regola "Una funzione dovrebbe eseguire una sola operazione".


Direi: show customer panel iff the user/customer is enabled. Sono d'accordo sul fatto che potrebbero esserci molte condizioni più complesse non facili da leggere come il tuo esempio, tuttavia, in quei casi le suddividerei in righe diverse.
ComFreek,

5

Credo che l' alternativa Hide()/ Show()sia attraente perché è più facile capire cosa sta succedendo che con SetVisible(true), mentre avere una singola funzione è preferibile perché evita molti condizionali.

In tal caso, suggerisco di utilizzare un elenco come input per SetVisible, in modo da ottenere SetVisible(Visibility.Visible)o SetVisible(Visibility.Hidden). Hai un'unica funzione che puoi leggere all'istante quale azione è stata intrapresa.

Usando le convenzioni di denominazione di Java, potresti avere setVisible(Visibility.VISIBLE)o setVisible(Visibility.HIDDEN).


3

Concordo con la risposta di Darien, ma volevo aggiungere un punto di vista dal punto di vista dei programmatori C #.

Quando vedo il codice che dice 'setXXX', leggo che per dire che sta impostando un valore su una cosa, non mi aspetto che ciò abbia effetti collaterali in quella cosa oltre all'impostazione di quel valore, e mi aspetto che sia idempotente (cioè posso continuare a impostarlo con lo stesso valore ed è ok). È piuttosto come accedere a un campo. In genere mi aspetto anche di vedere un metodo "getXXX" insieme a un "setXXX".

Non so se questo è quello che ti aspetti in Java e C ++, ma è quello che mi aspetterei in C #, anche se in C # c'è una scorciatoia per questo chiamato Proprietà. Ed ecco alcune belle indicazioni su come usare Proprietà ( http://msdn.microsoft.com/en-us/library/ms182181.aspx ).

Dato questo punto di vista, l'interfaccia che sceglierei dipende esclusivamente dalla presenza di effetti collaterali (oltre alla modifica del valore di quel campo):

Se l'esecuzione dell'azione ha effetti collaterali, ad esempio mostra una finestra di dialogo, sceglierei "Show ()" e "Hide ()".

Se non ha effetti collaterali, supponiamo che sto impostando la visibilità di un "widget" e qualcos'altro rende quel widget in base al suo stato, quindi userei setVisibility o setIsVisible. (Non lo chiamerei SetVisible).

In C # (non sono sicuro di Java) è abbastanza comune adottare un modello di osservatore, in cui un framework dell'interfaccia utente ascolterà le modifiche agli oggetti e riattiverà automaticamente l'interfaccia quando una proprietà come Visibilità cambia. Ciò significa che l'impostazione del valore chiamando setIsVisible appare come se avesse effetti collaterali, ma nella mia definizione non lo è. Il contratto del widget viene eseguito impostando il valore del campo che rappresenta "IsVisible".

Detto in altro modo, per me va bene attivare la visibilità di un'etichetta su un modulo prima che il modulo venga mostrato. Vale a dire label.getIsVisible == true, ma il modulo non viene visualizzato.

Non va bene per me chiamare Hide () quando il modulo non viene visualizzato.


1
La tua descrizione getXXX()e i setXXX()metodi come un modo per accedere a un campo senza effetti collaterali suona come Java e non C #. Questo è il modo in cui devi farlo in Java perché non ha proprietà. Se vedessi un codice del genere in C #, immagino che fosse stato scritto da uno sviluppatore Java che non aveva ancora imparato a conoscere le proprietà in C #.
gilly3,

+1 per SetVisibility.
Akaltar

@ gilly3 - Sì, certo. E "Proprietà" non esistono nel CLR, C # si traduce in chiamate di metodo get_XXX e set_YYY in IL. Il mio punto è: nel contesto della domanda, se vedessi setXXX, getXXX in Java ti aspetteresti che funzioni con la stessa semantica delle proprietà in C #. Stando così le cose, allora penso che le stesse linee guida per le proprietà in C # siano applicabili alle coppie di setXXX e getXXX in Java. Mi capita di concordare con le linee guida che faccio riferimento nel post, e quindi sto sostenendo quelle stesse linee guida per l'uso in questo scenario in Java quando definisco l'interfaccia.
Daniel James Bryars,

1
Potrebbe aiutare a chiarire che quando si intende "effetti collaterali", si intende "diverso da quelli associati all'essere una cosa" osservabile "". La regola che preferisco è quella di dire che se una getXXchiamata ha un setXXmetodo corrispondente , allora setYYnon dovrebbe influire su di essa, ma potrebbe influire su una getZZchiamata che non ha un setZZmetodo.
supercat

2

Suggerirei un'interfaccia leggermente modificata:

Show();
Hide();
ToggleVisible();
ToggleVisible(bool visible);

Nomi migliori

Questi nomi di metodo aiutano lo sviluppatore a decidere quale metodo utilizzare in base a ciò che deve essere fatto. Considerando che SetVisible(bool visible)può confondere uno sviluppatore perché trasmette lo stesso significato semantico di Show()e Hide(), Toggle()implica l'esistenza di una condizione che determina l'azione. Diventa quindi intuitivo per lo sviluppatore quando utilizzare ciascun metodo.

Ridondanza del codice ridotta

Il vantaggio di avere più metodi nell'interfaccia è che semplifica il codice chiamante. Potresti semplicemente esporre Show()e Hide(), ma:

  • Probabilmente avresti bisogno di un qualche SetVisible()metodo privato per fare il vero lavoro dietro le quinte (o scrivere codice ridondante per Show()e Hide()).
  • Il codice chiamante potrebbe avere molti blocchi if / else ridondanti solo per scegliere quale metodo usare. Questo gonfia il codice secondo me.
  • Se fossi il consumatore, probabilmente scriverei la mia funzione wrapper che fa ciò che SetVisible()(o Toggle()) già fa per evitare il gonfiamento del codice (odio il codice ridondante). Duplicando così un metodo che probabilmente esiste già come metodo privato nell'implementazione.

1
La duplicazione del metodo sembra ragionevole, anche se non lo farei da solo. D'altra parte, non sono d'accordo sul fatto che toggleVisible (bool) sia intuitivo. Per me, significa che dovrebbe cambiare se il bool passato è vero, il che sarebbe piuttosto strano, ma ho visto straniero. Non darebbe per scontato che sia davvero una funzione impostata sotto mentite spoglie.
Patrick M,

0

Suggerirei di usare SetVisible(bool)se solo solo se si cambia la visibilità due volte (mostra e nascondi, o nascondi e ri-mostra) lascerebbe le cose nello stesso stato essenzialmente prima dell'operazione (va bene se mostra e nascondi qualcosa o viceversa lascia gli oggetti che necessitano di un ridisegno, purché ci si possa aspettare che accada "automaticamente"). Se nascondere e mostrare un oggetto non avrà alcun effetto se non quello di cambiare un bit di stato, allora avrebbe senso un codice esterno per avere alcuni metodi che accettano un parametro di visibilità, e la scrittura di tale codice sarà facilitata SetVisible.

Se nascondere e mostrare nuovamente un oggetto potrebbe avere effetti collaterali come la modifica dell'ordine Z, è più probabile che tali azioni vengano eseguite con metodi separati. In tali casi, l'utilità di metodi esterni che accettano un parametro di "visibilità" sarà limitata e quindi ci saranno pochi vantaggi nel facilitarli. Inoltre, un SetVisiblemetodo suggerirà (erroneamente) che le modifiche alla visibilità degli oggetti possono essere realizzate senza effetti collaterali.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.