Zaimplementowanie tworzenia łańcuchów na fasoli jest bardzo przydatne: nie trzeba przeciążać konstruktorów, mega konstruktorów, fabryk i zapewnia większą czytelność. Nie mogę wymyślić żadnych wad, chyba że chcesz, aby twój obiekt był niezmienny , w którym to przypadku i tak nie miałby żadnych ustawień. Czy jest więc powód, dla którego nie jest to konwencja OOP?
public class DTO {
private String foo;
private String bar;
public String getFoo() {
return foo;
}
public String getBar() {
return bar;
}
public DTO setFoo(String foo) {
this.foo = foo;
return this;
}
public DTO setBar(String bar) {
this.bar = bar;
return this;
}
}
//...//
DTO dto = new DTO().setFoo("foo").setBar("bar");
myCustomDTO = DTOBuilder.defaultDTO().withFoo("foo").withBar("bar").Build();
Zrobiłbym to, aby nie kolidować z ogólną ideą, że setery są puste.new Foo().setBar('bar').setBaz('baz')
wydaje się to bardzo „płynne”. Mam na myśli, że można go zaimplementować dokładnie w ten sam sposób, ale bardzo bym się spodziewał, że przeczytam coś więcejFoo().barsThe('bar').withThe('baz').andQuuxes('the quux')
Odpowiedzi:
Moje najlepsze przypuszczenie: ponieważ narusza CQS
Masz polecenie (zmieniające stan obiektu) i zapytanie (zwracające kopię stanu - w tym przypadku samego obiektu) zmieszane w tę samą metodę. To niekoniecznie problem, ale narusza niektóre podstawowe wytyczne.
Na przykład w C ++ std :: stack :: pop () jest poleceniem, które zwraca void, a std :: stack :: top () jest zapytaniem, które zwraca odwołanie do górnego elementu na stosie. Klasycznie chciałbyś połączyć oba, ale nie możesz tego zrobić i być wyjątkowo bezpiecznym. (Nie jest to problem w Javie, ponieważ operator przypisania w Javie nie rzuca).
Gdyby DTO był typem wartości, możesz osiągnąć podobny koniec
Również łańcuchowe wartości zwrotne są kolosalnym bólem w czasie, gdy mamy do czynienia z dziedziczeniem. Zobacz „Ciekawie powtarzający się wzór szablonu”
Wreszcie jest problem, że domyślny konstruktor powinien pozostawić obiekt w prawidłowym stanie. Jeśli musisz uruchomić kilka poleceń, aby przywrócić prawidłowy stan obiektu, coś poszło bardzo źle.
źródło
abstract
T getSelf()
metodę ze zwrotem typu ogólnego. Teraz, zamiast wracaćthis
z twoich seterów, ty,return getSelf()
a następnie każda nadrzędna klasa po prostu sprawia, że typ jest sam w sobie ogólny i wracathis
zgetSelf
. W ten sposób ustawiający zwracają typ rzeczywisty, a nie typ deklarujący.Zapisanie kilku naciśnięć klawiszy nie jest atrakcyjne. Może to być miłe, ale konwencje OOP bardziej troszczą się o koncepcje i struktury, a nie klawisze.
Zwracana wartość nie ma znaczenia.
Co więcej, nie ma znaczenia, wartość zwracana jest myląca, ponieważ użytkownicy mogą oczekiwać, że wartość zwrotna będzie miała znaczenie. Mogą oczekiwać, że jest to „niezmienny seter”
W rzeczywistości Seter mutuje obiekt.
Nie działa dobrze z dziedziczeniem.
Umiem pisać
ale nie
Dla mnie najważniejsze są numery od 1 do 3. Dobrze napisany kod nie dotyczy przyjemnie ułożonego tekstu. Dobrze napisany kod dotyczy podstawowych pojęć, relacji i struktury. Tekst jest jedynie zewnętrznym odzwierciedleniem prawdziwego znaczenia kodu.
źródło
public class Foo<T extends Foo> {...}
po powrocie seteraFoo<T>
. Także te metody „ustawiające”, wolę nazywać je „metodami”. Jeśli przeciążenie działa dobrze, to po prostuFoo<T> with(Bar b) {...}
w przeciwnym razieFoo<T> withBar(Bar b)
.Nie sądzę, że jest to konwencja OOP, jest bardziej związana z projektowaniem języka i jego konwencjami.
Wygląda na to, że lubisz używać Java. Java ma specyfikację JavaBeans, która określa typ zwracany przez setter, który ma być nieważny, tzn. Jest w konflikcie z łańcuchem seterów. Ta specyfikacja jest powszechnie akceptowana i wdrażana w różnych narzędziach.
Oczywiście możesz zapytać, dlaczego nie jest częścią łańcucha specyfikacji. Nie znam odpowiedzi, może ten wzór nie był wtedy znany / popularny.
źródło
Object
, co może spowodować zwrócenie singletonu typuVoid
, jeśli metoda określavoid
jako typ zwracany. W innych wiadomościach najwyraźniej „pozostawienie komentarza, ale nie głosowanie” jest podstawą do niepowodzenia audytu „pierwszego postu”, nawet jeśli jest to dobry komentarz. Winię za to shoga.Jak powiedzieli inni ludzie, jest to często nazywane płynnym interfejsem .
Zwykle ustawiacze są zmiennymi przekazującymi wywołania w odpowiedzi na kod logiczny w aplikacji; twoja klasa DTO jest tego przykładem. Konwencjonalny kod, gdy setery nie zwracają niczego, jest w tym przypadku normalny. Inne odpowiedzi wyjaśniły sposób.
Jednak istnieje kilka przypadków, w których płynny interfejs może być dobrym rozwiązaniem, mają one wspólne.
Konfigurowanie konfiguracji, na przykład płynnie-nhibernate
Konfigurowanie danych testowych w testach jednostkowych przy użyciu specjalnych TestDataBulderClasses (Mother Object)
Jednak stworzenie dobrego płynnego interfejsu jest bardzo trudne , więc warto go tylko wtedy, gdy masz wiele „statycznych” ustawień. Również płynnego interfejsu nie należy mieszać z „normalnymi” klasami; stąd często stosuje się wzorzec konstruktora.
źródło
Myślę, że wiele powodów, dla których nie jest konwencją łączenia setera za drugim, jest takie, że w takich przypadkach bardziej typowe jest widzenie obiektu opcji lub parametrów w konstruktorze. C # ma również składnię inicjalizacyjną.
Zamiast:
Można napisać:
(w JS)
(w C #)
(w Javie)
setFoo
isetBar
wtedy nie są już potrzebne do inicjalizacji i mogą być później wykorzystane do mutacji.Chociaż w niektórych przypadkach przydatność łańcuchowa jest przydatna, ważne jest, aby nie próbować umieszczać wszystkiego w jednym wierszu tylko ze względu na redukcję znaków nowego wiersza.
Na przykład
utrudnia czytanie i rozumienie, co się dzieje. Przeformatowanie do:
Jest znacznie łatwiejszy do zrozumienia i sprawia, że „błąd” w pierwszej wersji jest bardziej oczywisty. Po przekształceniu kodu do tego formatu nie ma żadnej rzeczywistej przewagi nad:
źródło
/
do reprezentowania podziału linii]With Foo(1234) / .x = 23 / .y = 47
byłoby równoważneDim temp=Foo(1234) / temp.x = 23 / temp.y = 47
. Taka składnia nie powoduje dwuznaczności, ponieważ.x
sama w sobie nie może mieć innego znaczenia niż wiązanie się z bezpośrednio otaczającą instrukcją „With” [jeśli nie ma, lub obiekt nie ma elementux
, to.x
jest bez znaczenia]. Oracle nie umieściło czegoś takiego w Javie, ale taka konstrukcja idealnie pasowałaby do języka.Ta technika jest faktycznie używana we wzorze Konstruktora.
Ogólnie jednak unika się go, ponieważ jest niejednoznaczny. Nie jest oczywiste, czy zwracana wartość to obiekt (aby można było wywoływać inne obiekty ustawiające), czy też zwracany obiekt to właśnie przypisana wartość (również wspólny wzorzec). W związku z tym Zasada najmniejszej niespodzianki sugeruje, że nie powinieneś próbować zakładać, że użytkownik chce zobaczyć jedno lub drugie rozwiązanie, chyba że jest to fundamentalne dla projektu obiektu.
źródło
Obj* x = doSomethingToObjAndReturnIt(new Obj(1, 2, 3));
mi się, że zyskał także popularność, ponieważ odzwierciedlaa = b = c = d
, choć nie jestem przekonany, czy popularność była dobrze uzasadniona. Widziałem ten, o którym wspomniałeś, zwracający poprzednią wartość, w niektórych bibliotekach operacji atomowych. Morał historii? Jest to nawet bardziej mylące niż mi się wydawało =)new BetterText(string).indent(4).box().print();
. W takim przypadku ominąłem garść gobbledygooka i wziąłem ciąg znaków, wyciąłem go, zapakowałem i wysłałem. Możesz nawet chcieć metody duplikacji w kaskadzie (takiej jak, powiedzmy,.copy()
), aby umożliwić wszystkim kolejnym działaniom nie modyfikowanie oryginału.To bardziej komentarz niż odpowiedź, ale nie mogę komentować, więc ...
chciałem tylko wspomnieć, że to pytanie mnie zaskoczyło, ponieważ nie uważam tego za rzadkie . Właściwie w moim środowisku pracy (web developer) jest bardzo powszechne.
Na przykład, to jak symfony doctrine: generate: podmioty polecenia auto generuje wszystko
setters
, domyślnie .jQuery łączy większość swoich metod w bardzo podobny sposób.
źródło
JAB
. W latach college'u patrzyłem na JS jako na obrzydliwy, niedoszły język skryptowy, ale po kilku latach pracy z nim i nauce WŁAŚCIWEGO sposobu korzystania z niego, zacząłem ... naprawdę go kocham . I myślę, że dzięki ES6 stanie się naprawdę dojrzałym językiem. Ale co skłoniło mnie do odwrócenia głowy ... co moja odpowiedź ma wspólnego z JS? ^^ U