Kiedy stosować łańcuchy?
Tworzenie łańcuchów funkcji jest najbardziej popularne w językach, w których powszechne jest IDE z autouzupełnianiem. Na przykład prawie wszyscy programiści C # używają programu Visual Studio. Dlatego jeśli programujesz w języku C #, dodawanie łańcuchów do swoich metod może być oszczędnością czasu dla użytkowników tej klasy, ponieważ Visual Studio pomoże ci w budowaniu łańcucha.
Z drugiej strony, języki takie jak PHP, które są z natury bardzo dynamiczne i często nie mają obsługi autouzupełniania w IDE, zobaczą mniej klas obsługujących tworzenie łańcuchów. Tworzenie łańcuchów będzie odpowiednie tylko wtedy, gdy do ujawnienia metod łańcuchowych zostaną użyte poprawne phpDocs.
Co to jest łączenie?
Biorąc pod uwagę klasę o nazwie, Foo
dwie następujące metody są łańcuchowe.
function what() { return this; }
function when() { return new Foo(this); }
Fakt, że jest to odniesienie do bieżącej instancji i tworzy się nową instancję, nie zmienia faktu, że są to metody łańcuchowe.
Nie ma złotej zasady, że metoda łańcuchowa musi odwoływać się tylko do bieżącego obiektu. Rzeczywiście, metody łańcuchowe mogą być w dwóch różnych klasach. Na przykład;
class B { function When() { return true; } };
class A { function What() { return new B(); } };
var a = new A();
var x = a.What().When();
W this
żadnym z powyższych przykładów nie ma odniesienia . Kod a.What().When()
jest przykładem łączenia. Co ciekawe, typ klasy B
nigdy nie jest przypisywany do zmiennej.
Metoda jest łączona łańcuchowo, gdy jej wartość zwracana zostanie wykorzystana jako następny składnik wyrażenia.
Oto kilka innych przykładów
// return value never assigned.
myFile.Open("something.txt").Write("stuff").Close();
// two chains used in expression
int x = a.X().Y() * b.X().Y();
// a chain that creates new strings
string name = str.Substring(1,10).Trim().ToUpperCase();
Kiedy stosować this
inew(this)
Ciągi znaków w większości języków są niezmienne. Tak więc wywołania metod łączenia zawsze skutkują tworzeniem nowych ciągów. Gdzie jako obiekt taki jak StringBuilder może być modyfikowany.
Spójność jest najlepszą praktyką.
Jeśli masz metody modyfikujące stan obiektu i zwracające this
, nie mieszaj metod zwracających nowe instancje. Zamiast tego utwórz specjalną metodę o nazwie Clone()
, która zrobi to jawnie.
var x = a.Foo().Boo().Clone().Foo();
To jest o wiele jaśniejsze, co dzieje się w środku a
.
Krok na zewnątrz i do tyłu
Nazywam to lewą i lewą sztuczką, ponieważ rozwiązuje wiele typowych problemów związanych z łańcuchem. Zasadniczo oznacza to, że wychodzisz z oryginalnej klasy do nowej klasy tymczasowej, a następnie wracasz do oryginalnej klasy.
Klasa tymczasowa istnieje tylko w celu zapewnienia specjalnych cech oryginalnej klasie, ale tylko w szczególnych warunkach.
Często zdarza się, że łańcuch musi zmienić stan , ale klasa A
nie może reprezentować wszystkich tych możliwych stanów . Tak więc podczas łańcucha wprowadzana jest nowa klasa, która zawiera odniesienie do A
. To pozwala programiście wejść w stan i wrócić do A
.
Oto mój przykład, niech stan specjalny będzie znany jako B
.
class A {
function Foo() { return this; }
function Boo() { return this; }
function Change() return new B(this); }
}
class B {
var _a;
function (A) { _a = A; }
function What() { return this; }
function When() { return this; }
function End() { return _a; }
}
var a = new A();
a.Foo().Change().What().When().End().Boo();
To jest bardzo prosty przykład. Jeśli chcesz mieć większą kontrolę, możesz B
wrócić do nowego supertypu, A
który ma różne metody.
return this
. Jak mogę pomóc użytkownikom moich bibliotek poradzić sobie i zrozumieć tę sytuację? (Pozwalając im na łączenie metod, nawet jeśli nie jest to wymagane, czy to naprawdę byłoby w porządku? Czy powinienem trzymać się tylko jednego sposobu, w ogóle wymagać zmiany?)W zależności od języka posiadanie metod zwracających
void
/unit
i modyfikujących ich instancję lub parametry nie jest idiomatyczne. Nawet w językach, w których robiono to częściej (C #, C ++), wychodzi z mody wraz z przejściem na bardziej funkcjonalne programowanie w stylu (obiekty niezmienne, czyste funkcje). Ale załóżmy, że jest na to dobry powód.W przypadku niektórych zachowań (pomyśl
x++
) oczekuje się, że operacja zwróci wynik, nawet jeśli modyfikuje zmienną. Ale to w dużej mierze jedyny powód, aby zrobić to sam.To zależy.
W językach, w których kopiowanie / nowe i zwracanie jest powszechne (C # LINQ i ciągi), wówczas zwracanie tego samego odwołania byłoby mylące. W językach, w których modyfikowanie i zwracanie jest powszechne (niektóre biblioteki C ++), kopiowanie byłoby mylące.
void
Najlepszym sposobem wyjaśnienia byłoby uczynienie podpisu jednoznacznym (poprzez zwracanie lub używanie konstrukcji języka takich jak właściwości). Po tym dobrze jest podać nazwę tak,SetFoo
aby pokazywała, że modyfikujesz istniejącą instancję. Ale kluczem jest utrzymanie idiomów języka / biblioteki, z którą pracujesz.źródło
Clear()
lubAdd()
dowolnego typu kolekcji zmodyfikują to samo wystąpienie i zwrócąvoid
. W obu przypadkach mówisz, że byłoby to mylące ...obj = myCollection.Where(x => x.MyProperty > 0).OrderBy(x => x.MyProperty);
?Where()
zwraca nowy obiekt kolekcji.OrderBy()
zwraca nawet inny obiekt kolekcji, ponieważ treść jest uporządkowana.IEnumerable
, ale żeby było jasne, nie są kopiami, a oni nie są zbiorami (z wyjątkiemToList
,ToArray
itp).ICollection
. Mój błąd.(Przyjąłem C ++ jako język programowania)
Dla mnie jest to głównie aspekt czytelności. Jeśli A, B, C są modyfikatorami, szczególnie jeśli jest to obiekt tymczasowy przekazywany jako parametr do jakiejś funkcji, np
w porównaniu do
Zarejestruj się, jeśli możesz odwołać odwołanie do zmodyfikowanej instancji, powiedziałbym „tak” i skierowałem cię na przykład do operatorów strumieni „>>” i „<<” ( http://www.cprogramming.com/tutorial/ operator_overloading.html )
źródło
Możesz również zastosować metodę łączenia łańcuchowego ze zwrotem kopii zamiast modyfikować return.
Dobrym przykładem C # jest string.Replace (a, b), który nie zmienia ciągu, na którym został wywołany, ale zamiast tego zwraca nowy ciąg, umożliwiając wesołe połączenie.
źródło