Pracuję nad kodem interfejsu użytkownika, w którym mam Action
klasę, coś takiego -
public class MyAction extends Action {
public MyAction() {
setText("My Action Text");
setToolTip("My Action Tool tip");
setImage("Some Image");
}
}
Kiedy ta klasa Action została utworzona, prawie zakładano, że Action
klasy nie będzie można dostosowywać (w pewnym sensie - jej tekst, etykieta lub obraz nie zostaną zmienione w żadnym miejscu w kodzie). Teraz potrzebujemy zmienić tekst akcji w pewnym miejscu w kodzie. Zasugerowałem więc, aby mój współpracownik usunął zakodowany tekst akcji z konstruktora i zaakceptował go jako argument, aby wszyscy byli zmuszeni przekazać tekst akcji. Coś takiego jak ten kod poniżej -
public class MyAction extends Action {
public MyAction(String actionText) {
setText(actionText);
setTooltip("My Action tool tip");
setImage("My Image");
}
}
Uważa jednak, że skoro setText()
metoda należy do klasy podstawowej, można ją elastycznie wykorzystać do przekazywania tekstu akcji wszędzie tam, gdzie tworzona jest instancja akcji. W ten sposób nie ma potrzeby zmiany istniejącej MyAction
klasy. Więc jego kod wyglądałby mniej więcej tak.
MyAction action = new MyAction(); //this creates action instance with the hardcoded text
action.setText("User required new action text"); //overwrite the existing text.
Nie jestem pewien, czy jest to właściwy sposób radzenia sobie z problemem. Myślę, że w wyżej wymienionym przypadku użytkownik i tak zamierza zmienić tekst, więc dlaczego nie zmusić go podczas konstruowania akcji? Jedyną korzyścią, jaką widzę w oryginalnym kodzie, jest to, że użytkownik może utworzyć klasę Action bez większego zastanowienia nad ustawieniem tekstu.
Odpowiedzi:
W rzeczywistości nie jest to korzyść, dla większości celów jest to wadą, aw pozostałych przypadkach nazwałbym to remisem. Co jeśli ktoś zapomni wywołać setText () po zakończeniu budowy? Co się stanie, jeśli tak jest w nietypowym przypadku, na przykład w programie obsługi błędów? Jeśli chcesz naprawdę wymusić ustawienie tekstu, musisz wymusić go w czasie kompilacji, ponieważ tylko błędy w czasie kompilacji są tak naprawdę fatalne . Wszystko, co dzieje się w czasie wykonywania, zależy od wykonania określonej ścieżki kodu.
Widzę dwie wyraźne ścieżki naprzód:
null
lub pusty ciąg znaków, ale fakt, że nie przypisujesz tekstu, jest jawny, a nie domyślny. Łatwo jest dostrzec istnienienull
parametru i przekonać się, że pewnie było w nim trochę myśli, ale nie tak łatwo dostrzec brak wywołania metody i ustalić, czy brak takiego zamiaru był zamierzony, czy nie. W przypadku takiego prostego przypadku jest to prawdopodobnie podejście, które wybrałbym.źródło
Przeciążenie konstruktora byłoby tutaj prostym i bezpośrednim rozwiązaniem:
Jest to lepsze niż dzwonienie
.setText
później, ponieważ w ten sposób nic nie musi zostać nadpisane,actionText
od samego początku może być zamierzoną rzeczą.W miarę ewolucji twojego kodu będziesz potrzebował jeszcze większej elastyczności (co na pewno się wydarzy), skorzystasz z wzorca fabrycznego / konstruktora sugerowanego przez inną odpowiedź.
źródło
Dodaj płynną metodę „setText”:
Co może być bardziej zrozumiałe? Jeśli zdecydujesz się dodać kolejną dostosowywalną właściwość, nie ma problemu.
źródło
setText()
jest on zdefiniowany w klasie Action, z której dziedziczy MyAction. Prawdopodobnie ma już typ nieważnego zwrotu.Tak jak powiedział Kevin Cline w swojej odpowiedzi, myślę, że najlepszą drogą jest stworzenie płynnego API . Chciałbym tylko dodać, że płynny interfejs API działa lepiej, gdy masz więcej niż jedną właściwość, której możesz użyć.
Uczyni twój kod bardziej czytelnym, a moim zdaniem łatwiejszym i, aham , „seksownym” do pisania.
W twoim przypadku wyglądałoby to tak (przepraszam za literówkę, minął rok odkąd napisałem mój ostatni program Java):
A użycie byłoby takie:
źródło
Porady dotyczące używania konstruktorów lub konstruktorów są ogólnie dobre, ale z mojego doświadczenia wynika, że brakuje niektórych kluczowych punktów dla akcji, które
Zdecydowanie sugeruję, aby nazwa, etykietka narzędzia, ikona itp. ... zostały odczytane z pliku właściwości, XML itp. Na przykład w przypadku akcji otwierania pliku można przekazać właściwości i szukałaby
Jest to format dość łatwy do przetłumaczenia na francuski, wypróbowania nowej lepszej ikony itp. Bez czasu programisty lub ponownej kompilacji.
To tylko ogólny zarys, wiele pozostawia czytelnikowi ... Poszukaj innych przykładów internacjonalizacji.
źródło
Bezużyteczne jest wywoływanie setText (actionText) lub setTooltip („Wskazówka dla mojej akcji”) wewnątrz konstruktora; jest łatwiej (i zyskujesz większą wydajność), jeśli po prostu zainicjujesz bezpośrednio odpowiednie pole:
Jeśli zmienisz actionText podczas życia odpowiedniego obiektu MyAction, powinieneś ustawić metodę ustawiającą; jeśli nie, zainicjuj pole tylko w konstruktorze bez podania metody ustawiającej.
Ponieważ podpowiedź i obraz są stałymi, traktuj je jak stałe; mieć pola:
W rzeczywistości, przy projektowaniu wspólnych obiektów (nie fasoli lub obiektów reprezentujących ściśle struktury danych), źle jest ustawić obiekty ustawiające i pobierające, ponieważ w pewnym sensie blokują one enkapsulację.
źródło
Myślę, że jest to prawdą, jeśli zamierzamy stworzyć ogólną klasę akcji (jak aktualizacja, która służy do aktualizacji pracownika, działu ...). Wszystko zależy od scenariusza. Jeśli zostanie utworzona konkretna klasa akcji (np. Aktualizacja pracownika) (używana wiele miejsc w aplikacji - Aktualizuj pracownika) z zamiarem zachowania tego samego tekstu, podpowiedzi i obrazu w każdym miejscu w aplikacji (ze względu na spójność). Można więc wykonać stałe kodowanie tekstu, podpowiedzi i obrazu w celu zapewnienia domyślnego tekstu, podpowiedzi i obrazu. Aby zapewnić większą elastyczność, aby je dostosować, powinien mieć odpowiednie metody ustawiające. Mając na uwadze tylko 10% miejsc, musimy to zmienić. Pobieranie tekstu akcji za każdym razem od użytkownika może powodować inny tekst za każdym razem dla tej samej akcji. Jak „Aktualizacja Emp”, „Aktualizacja pracownika”, „Zmiana pracownika” lub „Edycja pracownika”.
źródło
Pomyśl o tym, jak będą używane instancje, i skorzystaj z rozwiązania, które poprowadzi, a nawet zmusi użytkowników do korzystania z tych instancji we właściwy, a przynajmniej najlepszy sposób. Programista korzystający z tej klasy będzie miał wiele innych rzeczy do zmartwienia i przemyślenia. Ta klasa nie powinna dodawać do listy.
Na przykład, jeśli klasa MyAction ma być niezmienna po zbudowaniu (i ewentualnie innej inicjalizacji), nie powinna mieć metody ustawiającej. Jeśli przez większość czasu będzie używać domyślnego tekstu „My Action Text”, powinien istnieć konstruktor bez parametrów oraz konstruktor, który zezwala na tekst opcjonalny. Teraz użytkownik nie musi myśleć o prawidłowym użyciu klasy w 90% przypadków. Jeśli użytkownik zwykle powinien przemyśleć tekst, pomiń konstruktor bez parametrów. Teraz użytkownik jest zmuszony myśleć w razie potrzeby i nie może przeoczyć niezbędnego kroku.
Jeśli
MyAction
instancja musi być zmienna po pełnej budowie, to musisz ustawić tekst. Kuszące jest pominięcie ustawiania wartości w konstruktorze (zasada DRY - „Don't Repeat Yourself”), a jeśli wartość domyślna jest zwykle wystarczająco dobra, zrobiłbym to. Ale jeśli nie jest, wymaganie tekstu w konstruktorze zmusza użytkownika do zastanowienia się, kiedy powinien.Pamiętaj, że ci użytkownicy nie są głupi . Mają po prostu zbyt wiele prawdziwych problemów, którymi trzeba się martwić. Myśląc o „interfejsie” klasy, możesz sprawić, że nie stanie się on również prawdziwym problemem - i niepotrzebnym.
źródło
W poniższym proponowanym rozwiązaniu nadklasa jest abstrakcyjna i ma wszystkie trzy elementy ustawione na wartość domyślną.
Podklasa ma różne konstruktory, więc programista może ją utworzyć.
Jeśli użyty zostanie pierwszy konstruktor, wszystkie elementy będą miały wartości domyślne.
Jeśli używany jest drugi konstruktor, wartość początkowa jest przypisywana do elementu actionText, pozostawiając pozostałym dwóm elementom domyślną wartość ...
Jeśli używany jest trzeci konstruktor, tworzysz go z nową wartością dla actionText i toolTip, pozostawiając imageURl z wartością domyślną ...
I tak dalej.
źródło