Czy lepsze jest Show () + Hide () lub SetVisible (bool widoczne)?


59

Co jest lepsze i dlaczego? (Z punktu widzenia projektowania interfejsu):

a) Mieć dwa Show()i Hide()funkcje

b) Aby mieć jedną SetVisible(bool visible)funkcję

EDYCJA: Na przykład niektóre obiekty mają stan widoczności i ta funkcja służy do jego zmiany.

c) wszystkie trzy Show(), Hide(), SetVisible(bool visible)funkcje


4
W jakim kontekście? Zasadniczo to nie ma znaczenia
Aviv Cohn


6
Dlaczego nie masz ich wszystkich publicznie? Są przypadki, w których wiesz, że zawsze będą pokazywane lub ukryte, i są przypadki, w których chciałbyś warunkowo pokazać lub ukryć.
pllee

@pllee: To chyba bardzo dobra uwaga.
user3123061,

4
W Javie byłby ustawiony Widoczny, ukrywał się i pokazywał bez początkowej dużej litery.
Pierre Arlaud

Odpowiedzi:


81

Wolę SetVisible(bool visible), ponieważ pozwala mi pisać kod klienta w następujący sposób:

SetVisible(DetermineIfItShouldBeVisible());

zamiast pisać

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

SetVisiblePodejście może również umożliwić łatwiejsze wdrożenie. Na przykład, jeśli konkretna konkretna klasa po prostu deleguje metodę do swoich klas złożonych, SetVisibleoznacza to, że należy wdrożyć jedną metodę mniej.

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

25
Równolegle możesz również uczynić Visible właściwością, zakładając, że Twój język ją obsługuje. MyObject.Visible = false;wydaje mi się jeszcze bardziej intuicyjny niżMyObject.SetVisible(false);
Brian

9
@Brian Dla mnie jest mniej czytelny i debugowalny, ponieważ ukrywa zachowanie programu przed moimi oczami - podstawowe wywołanie metody - ale to inna historia. Java nie obsługuje tej składni, w każdym razie jest to kwestia preferencji i treningu wzroku.
ignis

10
SetVisible()nie sugeruje (dla mnie), że faktycznie coś wyświetlasz. Odczytuje to bardziej, jakbyś ustawiał właściwość widoczności obiektu, prawdopodobnie pozostawiając jej właściwość Refresh()lub Redisplay()metodę sprawdzania wartości tej właściwości w celu ustalenia, czy obiekt powinien zostać wyświetlony czy ukryty.
TMN

1
Niestety Java nie obsługuje właściwości takich jak C #, tylko pobierające i ustawiające, które widać powyżej.
theGreenCabbage

1
@TMN: Spodziewałbym się, że przy braku innych czynników uniemożliwiających widoczność (kolejność Z, widoczność rodzica, lokalizacja itp.) Uruchomi setVisible(true)proces, w którym obiekt zostanie narysowany, gdy system będzie dalej bezczynny, jeśli nie wcześniej. Spodziewałbym się, że refreshmoże to być przydatne, aby przyspieszyć wyświetlanie obiektu, ale że obiekt ostatecznie zostanie narysowany niezależnie (chyba że np. Ustawiono jego widoczność falseprzed tym).
supercat

35

Nie zgadzam się ze wszystkimi plakatami sugerującymi, że wiele funkcji do robienia tego samego jest dobrą rzeczą. Podczas gdy trzy funkcje zamiast jednego nie może wydawać się dużo wzdęć, pamiętaj, że twoja klasa jest prawdopodobne, aby skończyć z wielu takich funkcji (np setEnabled, enable, disable), a zatem tego podejścia będzie skończyć z dużo większej interfejsu klasy. Co więcej, jest prawdopodobne, że skończysz z wieloma podobnymi brzmiącymi funkcjami / właściwościami / czymkolwiek w twojej klasie, a mnożenie funkcji dodatkowo zaciemni, która z nich idzie z czym.

W językach, które obsługują właściwości, powinny być preferowane, ale skoro ani Java, ani C ++ nie robią tego, myślę, że to kwestia sporna.

Myślę, że setVisible()należy preferować z następujących powodów:

  1. Od razu widać, czym jest funkcja odwrotna. Aby odwrócić setVisible(false), zadzwoń, setVisible(true)podczas gdy przeciwieństwo hide()może być z łatwością reveal().
  2. Jest programowo prostszy za każdym razem, gdy określasz, który stan powinien przyjąć w kodzie, tzn. Możesz zadzwonić setVisible(wantToSee)zamiast używać ifinstrukcji.
  3. Gdy masz wiele podobnych funkcji, setX()format uogólnia, dzięki czemu możesz mieć zestaw spójnych funkcji, podczas gdy podejście sprawdzane tworzy wiele funkcji, które mogą być trudne do zlokalizowania, jeśli nie wiesz, czego szukasz. Spójność interfejsów API znacznie ułatwia ich naukę i zapamiętywanie.

3
C ++ nie ma właściwości, ale ma wolne funkcje, więc możesz rozszerzyć interfejs klasy bez dodawania nowych funkcji składowych, tj. Z mniejszym stopniem sprzężenia.
fresnel

Qt często zapewnia wszystkie trzy jako wygodę, dzięki czemu hide () i show () można łączyć bezpośrednio z innymi zdarzeniami za pomocą systemu sygnału / gniazda. Jest to naprawdę ograniczenie systemu automatów - gdyby używał czegoś bardziej przypominającego boost :: functions, argument prawda / fałsz mógłby zostać powiązany w momencie konfigurowania wywołania zwrotnego.

1
„W językach, które obsługują właściwości, powinny być preferowane, ale skoro ani Java, ani C ++ nie, to chyba kwestia sporna”. niekoniecznie. W przeciwieństwie do pobierających / ustawiających? Tak. Ale set_visible nie jest tak naprawdę Seterem.
Miles Rout

19

To zależy od tego, co Wyświetlanie i ukrywanie oznacza w kontekście. Najpierw chcesz dowiedzieć się, który z nich jest Twoją „główną drogą” i skupić się na rozwijaniu tego:

  • Powody, dla których warto wybrać setVisible(bool)
    • Jest to zwykły bit-flip, lub twój obiekt głównie trzyma stan
    • Twój obiekt będzie spędzał większość czasu w środowisku CRUD
    • Istnieje wiele łatwo udostępnianych kodów między pokazywaniem a ukrywaniem
  • Powody wyboru show()ihide()
    • Występują ważne skutki uboczne lub dużo logiki, na przykład gdy obiekt musi sprawdzić wszystkie swoje kontenery pod kątem ich widoczności lub uruchamia animację przejścia.
    • Czy jest to część modelu domeny, w którym ważne jest wyrażanie intencji

OK, więc teraz, gdy już zakodowałeś jej „złoty standard”, musisz dowiedzieć się, czy warto dodać cienkie metody wygody w innym stylu, aby ułatwić życie każdemu, kto będzie używał twojego obiektu.

  • Wygoda setVisible(bool)
    • Pozwala uniknąć instrukcji if, które mają trywialne warunki i wpływają tylko na widoczność (np. setVisible(a==b))
    • Może być podłączony do pewnych struktur getter / setter, jeśli jest to coś, czego się spodziewasz
  • Wygoda show()ihide()
    • Przydatny w języku z pierwszorzędnymi funkcjami i funkcjami zwrotnymi (np. onSuccess(widget.show))
    • Znacznie łatwiejszy do odczytania dzięki stosom śledzenia i profilowaniu wydajności, ponieważ można szybko zobaczyć, co program próbował zrobić

TLDR: Dowiedz się, który jest najważniejszy, zaimplementuj go, a następnie zadaj sobie pytanie, czy warto dodać drugi styl jako metody cienkiej wygody.


11

Powiedziałbym „wszystkie trzy”.

Show()i Hide()wydają się być łatwiejsze do odczytania niż SetVisible(true)i SetVisible(false). Jednak, jeśli chcesz ustawić logiczność widoczności, lepiej jest mieć metodę przyjmującą boolzamiast budować ifwokół niej bool.

Możesz obsłużyć wszystkie trzy bez powielania logiki i minimalnej płyty kotłowej:

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

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

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

Alternatywnie, jeśli rzeczy, które SetVisiblepakujesz, mają bardziej zaawansowany interfejs API:

void Show() {
    SetVisible(true);
}

void Hide() {
    SetVisible(false);
}

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

40
Microsoft stosuje to podejście do uruchamiania i zatrzymywania System.Windows.Forms.Timer. Osobiście uważam, że jest to mylące. Kiedy widzę oba Showi SetVisible, moją pierwszą skłonnością jest zastanawianie się, czy istnieje jakaś istotna różnica między tymi dwoma funkcjami.
Brian

1
Możesz je jednak łatwo udokumentować, aby wyeliminować to zamieszanie. Nie zrobiłem tego, ponieważ był to prosty przykład.
Garry Shutler,

20
Czy teraz muszę poświęcić X dodatkowych minut na przeczytanie dokumentacji, zanim będę mógł swobodnie korzystać z zajęć? Czy też muszę zmarnować X dodatkowych minut na pomieszanie (lub wprowadzanie błędów)? Jasne, X jest dość mały jak na takie rzeczy, ale na pewno nie jest zero. Oferowanie wszystkich 3 opcji oznacza oferowanie trzykrotnie większej liczby funkcji, niż to konieczne, co oznacza, że ​​spędzasz więcej pracy na dokumentacji, a ja spędzam więcej pracy na nauce korzystania z klasy. Ponadto wprowadza jeszcze jeden sposób, w jaki różni programiści mogą być niespójni podczas korzystania z klasy.
Brian

5
Jest to wyraźne naruszenie zasady segregacji interfejsu, jednej z zasad SOLID. Inna opinia przeciwko twojemu podejściu to ta autorstwa jarosława tulacha, projektanta netbeans, który wielokrotnie nalega na zapewnienie tylko jednego sposobu na zrobienie jednej rzeczy w API w swojej książce praktyczny projekt API.
AlfredoCasado

@AlfredoCasado Zgadzam się. Co jeśli SetVisible był chroniony ? Możesz uzyskać do niego dostęp z podklasy, ale wywołanie do danego obiektu z tym interfejsem (takim jak API) musiałoby być Ukryj / Pokaż.
Pierre Arlaud

5

Wolę show () i hide (), w rzeczywistości każda metoda, która odbiera jedną wartość logiczną, może zostać zmieniona dla dwóch metod, aby lepiej wyrażać intencję API. Na przykład Robert Martin w czystym kodzie poleca metody wolniejsze od zerowych argumentów od metod z jednym argumentem.

Innym ważnym argumentem jest dla mnie czytelność, moim zdaniem dobry kod można odczytać jak prozę, jego naprawdę dziwna proza ​​coś takiego jak „main_window setVisible false” zamiast „main_window hide”, piszesz lub mówisz w ten sposób normalnie ?, po co używać tego dziwnego konstruowanie języka w programach, gdy jest to całkowicie możliwe, użyj bardziej naturalnego języka ?.


1
Czy proza ​​Asemblera nie wystarczy?
Alexander

Spodziewałbym się, że sekwencja it.setVisible(false); it.setVisible(true);nie powinna wpływać na widoczność rodzica kontrolnego, ani nie powinna wpływać na kolejność Z ani lokalizację kontrolki. Dla kontrastu hide(); show(); może całkiem prawdopodobne zmusić rodzica kontrolnego do bycia widocznym, przesunąć go ponad inne kontrolki i ograniczyć jego pozycję do miejsca, które można zobaczyć. W niektórych przypadkach dobrze jest mieć pewność, że coś jest rzeczywiście widoczne (jak w przypadku wyżej wspomnianych show(), ale w innych przypadkach warto zmienić flagę widoczności bez zmiany czegokolwiek
supercat

W Object Oriented API nie ma „flag”, OO dotyczy przesyłania wiadomości, chodzi o to, aby powiedzieć, że inny obiekt wykonuje jakieś zadanie, a nie o zmianę „flag”, które są stanem obiektu. Robisz wiele założeń na temat kontroli, rodziców, porządkowania Z i rzeczy, których oczekujesz, prawdopodobnie na podstawie swoich wcześniejszych doświadczeń z innymi API, to bardzo zły pomysł, projektując API w oparciu o osobiste odczucia i założenia dotyczące domeny.
AlfredoCasado

5

Wierzę, że im bardziej metoda jest ekspresyjna, tym bardziej czytelny, a tym samym łatwiejszy do utrzymania kod będzie. Rozważ następujące dwa przypadki:

Przypadek 1:

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

Przypadek 2:

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

W pierwszym przypadku jasne jest, co robi funkcja „setVisible”, ale jeśli chcesz ją przeczytać, powiedziałbyś:

ustaw panel klienta na widoczny, jeśli klient jest włączony lub ustaw go na ukryty, jeśli klient jest wyłączony.

Chociaż jest bardziej opisowy, aby powiedzieć:

  • sprawdź status klienta:
    • jeśli klient jest włączony, pokaż panel klienta
    • w przeciwnym razie ukryj to

co spowoduje zmianę funkcji „Przypadek 1” na:

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

produkuje więcej kodu, ale jest bardziej czytelny.

Drugi przypadek ma oczywistą wadę, tzn. Już wiesz, że chcesz pokazać panel, więc dlaczego nie skorzystać z funkcji „Pokaż”?

Nie twierdzę, że użycie „setVisible” jest całkowicie błędne, ale staje się mylące, gdy próbujesz odczytać kod, który nie został napisany przez Ciebie z czasem, i nie jest zgodny z regułą „A funkcja powinna wykonać tylko jedną operację”.


Powiedziałbym: show customer panel iff the user/customer is enabled. Zgadzam się, że może być wiele bardziej skomplikowanych warunków, które nie są tak łatwe do odczytania jak twój przykład, jednak w takich przypadkach podzieliłbym te warunki na różne linie.
ComFreek

5

Uważam, że alternatywa Hide()/ Show()jest atrakcyjna, ponieważ łatwiej jest zrozumieć, co się dzieje, niż przy SetVisible(true)jednoczesnym korzystaniu z jednej funkcji, ponieważ pozwala uniknąć wielu warunków warunkowych.

Jeśli o to chodzi to proponuję stosując wyliczenie jako wkładu SetVisible, więc masz albo SetVisible(Visibility.Visible)albo SetVisible(Visibility.Hidden). Masz jedną funkcję, dzięki której możesz natychmiast odczytać, jakie działania są podejmowane.

Używając konwencji nazewnictwa Java, możesz mieć setVisible(Visibility.VISIBLE)lub setVisible(Visibility.HIDDEN).


3

Zgadzam się z odpowiedzią Dariena, ale chciałem dodać punkt widzenia z perspektywy programistów C #.

Kiedy widzę kod z napisem „setXXX”, czytam to, aby ustawić wartość dla rzeczy, nie oczekuję, że będzie to miało skutki uboczne w tej rzeczy innej niż ustawienie tej wartości, i spodziewam się, że będzie to idempotentne (tzn. mogę nadal ustawiać tę samą wartość i jest w porządku). To raczej jak dostęp do pola. Generalnie spodziewałbym się również zobaczyć metodę „getXXX” wraz z „setXXX”.

Nie wiem, czy tego się spodziewasz w Javie i C ++, ale tego oczekiwałbym w C #, choć w C # jest krótka ręka dla tego o nazwie Właściwości. A oto kilka dobrych wskazówek na temat korzystania z właściwości ( http://msdn.microsoft.com/en-us/library/ms182181.aspx ).

Biorąc pod uwagę ten widok, wybór interfejsu zależy wyłącznie od tego, czy występują jakieś skutki uboczne (inne niż zmiana tej wartości pola):

Jeśli wykonanie akcji ma skutki uboczne, na przykład pokazuje okno dialogowe, wybrałbym „Show ()” i „Hide ()”.

Jeśli nie ma efektów ubocznych, powiedzmy, że ustawiam widoczność „widżetu”, a coś innego renderuje ten widżet w zależności od jego stanu, wtedy użyłbym setVisibility lub setIsVisible. (Nie nazwałbym tego SetVisible).

W języku C # (nie jestem pewien co do Javy) dość często przyjmuje się wzorzec obserwatora, w którym struktura interfejsu użytkownika będzie nasłuchiwać zmian w obiektach i automatycznie ponownie renderuje interfejs użytkownika, gdy zmieni się właściwość, taka jak Widoczność. Oznacza to, że ustawienie wartości przez wywołanie setIsVisible wygląda tak, jakby miało skutki uboczne, ale w mojej definicji tak nie jest. Kontrakt widżetu jest wypełniany poprzez ustawienie jego wartości pola reprezentującej „IsVisible”.

Innymi słowy, w porządku jest dla mnie przełączanie widoczności etykiety na formularzu przed wyświetleniem formularza. Tj. Label.getIsVisible == true, ale formularz nie jest wyświetlany.

Wywoływanie Hide () nie jest w porządku, gdy formularz nie jest wyświetlany.


1
Twój opis getXXX()i setXXX()metody dostępu do pola bez skutków ubocznych brzmią jak Java, a nie C #. To jest sposób, w jaki należy to zrobić w Javie, ponieważ nie mają właściwości. Gdybym widział taki kod w C #, domyślam się, że został napisany przez programistę Java, który jeszcze nie dowiedział się o właściwościach w C #.
gilly3

+1 dla SetVisibility.
akaltar

@ gilly3 - Tak, oczywiście. I „Właściwości” nie istnieją w CLR, C # tłumaczy na wywołania metod get_XXX i set_YYY w IL. Chodzi mi o to: w kontekście pytania, jeśli widziałeś setXXX, getXXX w Javie, możesz oczekiwać, że będzie działał z taką samą semantyką jak właściwości w C #. Biorąc to pod uwagę, rozumiem zatem, że te same wytyczne dla właściwości w języku C # mają zastosowanie do par setXXX i getXXX w Javie. Zdarza się, że zgadzam się w wytycznych, do których odwołuję się w poście, i dlatego zalecam te same wytyczne do zastosowania w tym scenariuszu w Javie podczas definiowania interfejsu.
Daniel James Bryars

1
Pomocne może być wyjaśnienie, że gdy masz na myśli „skutki uboczne”, masz na myśli „inne niż związane z byciem„ obserwowalną ”rzeczą. Zasadą, którą preferuję, jest stwierdzenie, że jeśli getXXwywołanie ma odpowiednią setXXmetodę, to setYYnie powinno na nią wpływać, ale może wpływać na getZZwywołanie, które nie ma setZZmetody.
supercat

2

Sugeruję nieco zmodyfikowany interfejs:

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

Lepsze imiona

Te nazwy metod pomagają programistom zdecydować, której metody użyć, w zależności od tego, co należy zrobić. Natomiast SetVisible(bool visible)mogą mylić dewelopera, ponieważ przekazuje tę samą semantyczne znaczenie, jak Show()i Hide(), Toggle()zakłada istnienie warunku, który określa działania. W ten sposób staje się intuicyjne dla programisty, kiedy należy użyć każdej metody.

Zredukowana redundancja kodu

Zaletą posiadania wielu metod w interfejsie jest to, że upraszcza kod wywołujący. Możesz po prostu ujawnić Show()i Hide(), ale:

  • Prawdopodobnie potrzebujesz jakiejś SetVisible()prywatnej metody, aby wykonać prawdziwą pracę za kulisami (lub napisać zbędny kod dla Show()i Hide()).
  • Kod wywołujący może mieć wiele zbędnych bloków if / else tylko po to, aby wybrać metodę, której należy użyć. Moim zdaniem powoduje to rozdęcie kodu.
  • Gdybym był konsumentem, prawdopodobnie po prostu napisałbym własną funkcję opakowania, która robi to, co SetVisible()(lub Toggle()) już robi, aby uniknąć rozdęcia kodu (nienawidzę zbędnego kodu). W ten sposób powiela się metodę, która prawdopodobnie już istnieje jako metoda prywatna w implementacji.

1
Powielanie metody brzmi rozsądnie, chociaż sam bym tego nie zrobił. Z drugiej strony nie zgadzam się, że toggleVisible (bool) jest intuicyjny. Dla mnie oznacza to, że powinien się przełączać, jeśli przekazany bool jest prawdziwy, co byłoby raczej dziwne, ale widziałem obcego. Nie zakładałby, że to naprawdę ustawiona funkcja w przebraniu.
Patrick M

0

Sugerowałbym użycie, SetVisible(bool)jeśli w ogóle, tylko jeśli dwukrotne przełączenie widoczności (pokaż i ponownie ukryj lub ukryj i ponownie pokaż) pozostawiłoby rzeczy w zasadniczo takim samym stanie, jak przed wykonaniem operacji (w porządku, jeśli pokazywanie i ukrywanie coś lub vice versa pozostawia obiekty wymagające przerysowania, pod warunkiem, że można oczekiwać, że nastąpi to „automatycznie”). Jeśli ukrywanie i pokazywanie obiektu nie przyniesie żadnego innego efektu niż zmiana jednego bitu stanu, wówczas sensownym byłoby, aby kod zewnętrzny miał pewne metody, które akceptują parametr widoczności, a pisanie takiego kodu będzie ułatwione SetVisible.

Jeśli ukrywanie i ponowne pokazywanie obiektu może mieć skutki uboczne, takie jak zmiana kolejności Z, takie działania powinny być częściej wykonywane osobnymi metodami. W takich przypadkach przydatność metod zewnętrznych, które akceptują parametr „widoczności”, będzie ograniczona, a zatem ułatwienie ich będzie niewielkie. Co więcej, SetVisiblemetoda (błędnie) zasugeruje, że zmiany widoczności obiektów można osiągnąć bez skutków ubocznych.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.