Często próbuję zdecydować, który z tych dwóch sposobów użyć, gdy muszę użyć wspólnych danych w niektórych metodach w moich klasach. Jaki byłby lepszy wybór?
W tej opcji mogę utworzyć zmienną instancji, aby uniknąć konieczności deklarowania dodatkowych zmiennych, a także aby uniknąć definiowania parametrów metody, ale może nie być tak jasne, gdzie te zmienne są tworzone / modyfikowane:
public class MyClass {
private int var1;
MyClass(){
doSomething();
doSomethingElse();
doMoreStuff();
}
private void doSomething(){
var1 = 2;
}
private void doSomethingElse(){
int var2 = var1 + 1;
}
private void doMoreStuff(){
int var3 = var1 - 1;
}
}
A może po prostu tworzysz zmienne lokalne i przekazujesz je jako argumenty?
public class MyClass {
MyClass(){
int var1 = doSomething();
doSomethingElse(var1);
doMoreStuff(var1);
}
private int doSomething(){
int var = 2;
return var;
}
private void doSomethingElse(int var){
int var2 = var + 1;
}
private void doMoreStuff(int var){
int var3 = var - 1;
}
}
Jeśli odpowiedź brzmi, że oba są poprawne, który z nich jest widziany / używany częściej? Również, jeśli możesz podać dodatkowe zalety / wady dla każdej opcji, byłoby bardzo cenne.
java
coding-style
carlossierra
źródło
źródło
Odpowiedzi:
Dziwię się, że o tym jeszcze nie wspominałem ...
To zależy od tego, czy
var1
jest faktycznie częścią Twojego obiektu stanu .Zakładasz, że oba te podejścia są poprawne i że to tylko kwestia stylu. Mylisz się.
Chodzi wyłącznie o to, jak prawidłowo modelować.
Podobnie
private
istnieją metody instancji służące do mutowania stanu obiektu . Jeśli to nie jest twoja metoda, powinno byćprivate static
.źródło
transient
nie ma z tym nic wspólnego, ponieważtransient
dotyczy stanu trwałego , jak w częściach obiektu, które są zapisywane, gdy robisz coś takiego jak serializacja obiektu. Na przykład magazyn zaplecza ArrayList jesttransient
nawet niezwykle istotny dla stanu ArrayList, ponieważ podczas szeregowania ArrayList chcesz zapisać tylko tę część magazynu, która zawiera rzeczywiste elementy ArrayList, a nie wolne miejsce na końcu zarezerwowane dla dalszych uzupełnień elementów.var1
jest to potrzebne dla kilku metod, ale nie jest częścią stanuMyClass
, może być czas na umieszczenievar1
tych metod w innej klasie, z której będą korzystaćMyClass
.Nie wiem, co jest bardziej rozpowszechnione, ale zawsze robiłbym to drugie. Bardziej wyraźnie komunikuje przepływ danych i czas życia, i nie powoduje wzdęcia każdej instancji twojej klasy w polu, którego jedyny istotny czas życia występuje podczas inicjalizacji. Powiedziałbym, że to pierwsze jest mylące i znacznie utrudnia przegląd kodu, ponieważ muszę rozważyć możliwość modyfikacji dowolnej metody
var1
.źródło
Powinieneś ograniczyć zakres swoich zmiennych tak bardzo, jak to możliwe (i rozsądne). Nie tylko w metodach, ale ogólnie.
Twoje pytanie oznacza, że zależy to od tego, czy zmienna jest częścią stanu obiektu. Jeśli tak, można używać go w tym zakresie, tj. Całego obiektu. W takim przypadku wybierz pierwszą opcję. Jeśli nie, przejdź do drugiej opcji, ponieważ zmniejsza widoczność zmiennych, a tym samym ogólną złożoność.
źródło
Jest inny styl - użyj kontekstu / stanu.
Podejście to ma wiele zalet. Obiekty stanu mogą zmieniać się na przykład niezależnie od obiektu, dając dużo miejsca na przyszłość.
Jest to wzorzec, który działa również dobrze w systemie rozproszonym / serwerowym, w którym niektóre szczegóły muszą być zachowane podczas połączeń. Możesz przechowywać dane użytkownika, połączenia z bazą danych itp. W
state
obiekcie.źródło
Chodzi o skutki uboczne.
Pytanie o
var1
to, czy jest częścią państwa, nie ma sensu tego pytania. Jasne, jeślivar1
musi się utrzymywać, musi to być instancja. Można zastosować dowolne podejście, niezależnie od tego, czy konieczne jest wytrwałość.Podejście niepożądane
Niektóre zmienne instancji są używane tylko do komunikacji między prywatnymi metodami od wywołania do wywołania. Tego rodzaju zmienną instancji można zrefaktoryzować, ale nie musi tak być. Czasami rzeczy są z nimi wyraźniejsze. Ale nie jest to pozbawione ryzyka.
Wypuszczasz zmienną z jej zakresu, ponieważ jest ona używana w dwóch różnych zakresach prywatnych. Nie dlatego, że jest potrzebny w zakresie, w którym go umieszczasz. To może być mylące. „Globale są złe!” poziom dezorientacji. To może działać, ale po prostu nie będzie dobrze skalować. Działa tylko w małych. Żadnych dużych przedmiotów. Bez długich łańcuchów spadkowych. Nie powoduj efektu jo-jo .
Podejście funkcjonalne
Teraz, nawet jeśli
var1
musi się utrzymywać, nic nie mówi, że musisz użyć, jeśli dla każdej przejściowej wartości, którą może przyjąć, zanim osiągnie stan, który chcesz zachować między połączeniami publicznymi. Oznacza to, że nadal możesz ustawićvar1
instancję, używając jedynie funkcjonalnych metod.Więc część stanu, czy nie, nadal możesz zastosować jedno z dwóch podejść.
W tych przykładach „var1” jest tak enkapsulowane, że oprócz tego, że debugger wie, że istnieje. Zgaduję, że zrobiłeś to celowo, ponieważ nie chcesz nas uprzedzić. Na szczęście nie obchodzi mnie które.
Ryzyko skutków ubocznych
To powiedziawszy, wiem skąd pochodzi twoje pytanie. Pracowałam pod nędznym yo yo „ing dziedziczenie że mutuje zmiennej instancji na wielu poziomach w różnych metod i znika squirrelly próbując go śledzić. To jest ryzyko.
To ból popycha mnie do bardziej funkcjonalnego podejścia. Metoda może udokumentować swoje zależności i dane wyjściowe w sygnaturze. To potężne, jasne podejście. Pozwala także zmienić to, co przekazujesz prywatną metodą, dzięki czemu jest łatwiejsza do wykorzystania w klasie.
Pozytywne skutki uboczne
To także ogranicza. Czyste funkcje nie mają skutków ubocznych. To może być dobra rzecz, ale nie jest zorientowana obiektowo. Dużą częścią orientacji obiektowej jest możliwość odniesienia się do kontekstu poza metodą. Robienie tego bez przeciekania globali tutaj i po nich jest siłą OOP. Mam elastyczność globalną, ale jest ładnie zawarta w klasie. Mogę wywołać jedną metodę i mutować każdą zmienną instancji na raz, jeśli chcę. Jeśli to zrobię, jestem zobowiązany przynajmniej podać nazwę metody, która wyjaśnia, co się dzieje, aby ludzie nie byli zaskoczeni, gdy to się stanie. Komentarze również mogą pomóc. Czasami te komentarze są sformalizowane jako „warunki postowe”.
Minusem funkcjonalnych metod prywatnych
Podejście funkcjonalne wyjaśnia niektóre zależności. Chyba że jesteś w czysto funkcjonalnym języku, nie może wykluczyć ukrytych zależności. Nie wiesz, patrząc tylko na sygnaturę metod, że nie ukrywa to przed tobą efektu ubocznego w pozostałej części kodu. Po prostu nie.
Post warunkowe
Jeśli ty i wszyscy inni w zespole niezawodnie udokumentuje skutki uboczne (warunki przed / po) w komentarzach, zysk z podejścia funkcjonalnego jest znacznie mniejszy. Tak, wiem, śnij dalej.
Wniosek
Osobiście wolę funkcjonalne metody prywatne w obu przypadkach, jeśli mogę, ale szczerze mówiąc jest to głównie dlatego, że te komentarze warunkowe przed / po warunkowe efekty uboczne nie powodują błędów kompilatora, gdy są przestarzałe lub gdy metody są wywoływane w niewłaściwym porządku. Chyba że naprawdę potrzebuję elastyczności efektów ubocznych, wolałbym tylko wiedzieć, że coś działa.
źródło
var1
jako zmiennej stanu przez zmianę paradygmatów. Zakres klasy NIE jest tylko miejscem przechowywania stanu. Jest to również zakres obejmujący. Oznacza to, że istnieją dwie możliwe motywacje, aby umieścić zmienną na poziomie klasy. Możesz twierdzić, że robisz to tylko dla ograniczonego zakresu, a państwo nie jest złe, ale mówię, że jest to kompromis z arią, która jest również zła. Wiem to, ponieważ musiałem utrzymywać kod, który to robi. Niektóre zostały zrobione dobrze. Niektóre były koszmarem. Linia między nimi nie jest stanem. To czytelność.Pierwszy wariant wygląda na nieintuicyjny i potencjalnie niebezpieczny dla mnie (wyobraź sobie, z jakiegokolwiek powodu ktoś upublicznia twoją prywatną metodę).
Wolałbym raczej utworzyć twoje zmienne po zbudowaniu klasy lub przekazać je jako argumenty. Ten ostatni daje możliwość używania funkcjonalnych idiomów i nie polegania na stanie obiektu zawierającego.
źródło
Istnieją już odpowiedzi mówiące o stanie obiektu i kiedy preferowana jest druga metoda. Chcę tylko dodać jeden typowy przypadek użycia dla pierwszego wzoru.
Pierwszy wzorzec jest całkowicie poprawny, gdy wszystko, co robi twoja klasa, polega na tym, że zawiera on algorytm . Jednym z przykładów użycia jest to, że jeśli napisałeś algorytm do jednej metody, byłby on zbyt duży. Więc dzielisz go na mniejsze metody, czynisz z niego klasę, a metody podrzędne są prywatne.
Przekazywanie całego stanu algorytmu przez parametry może być uciążliwe, dlatego korzystasz z prywatnych pól. Jest to również zgodne z regułą z pierwszego akapitu, ponieważ jest to zasadniczo stan instancji. Musisz tylko pamiętać i odpowiednio udokumentować, że algorytm nie jest ponownie wysyłany, jeśli użyjesz do tego prywatnych pól . To nie powinno być problemem przez większość czasu, ale może cię ugryźć.
źródło
Spróbujmy przykładu, który coś robi. Wybacz mi, ponieważ to jest javascript, a nie Java. Punkt powinien być taki sam.
Odwiedź https://blockly-games.appspot.com/pond-duck?lang=en , kliknij kartę javascript i wklej to:
Należy zauważyć, że
dir
,wid
idis
nie są coraz przeszedł wokół partii. Należy również zauważyć, że kod w funkcji, któralock()
zwraca, przypomina pseudo kod. To jest rzeczywisty kod. Ale jest bardzo łatwy do odczytania. Możemy dodać przekazywanie i przypisywanie, ale dodałoby to bałaganu, którego nigdy nie zobaczysz w pseudo-kodzie.Jeśli chcesz argumentować, że nie wykonanie przypisania i przekazania jest w porządku, ponieważ te trzy zmienne są stanem trwałym, rozważ przeprojektowanie, które przypisuje
dir
losową wartość każdej pętli. To nie jest teraz trwałe, prawda?Jasne, teraz moglibyśmy teraz zmniejszyć
dir
zakres, ale nie bez konieczności zaśmiecania naszego pseudo-podobnego kodu przekazywaniem i ustawianiem.Więc nie, stan nie jest powodem, dla którego decydujesz się użyć lub nie użyć efektów ubocznych zamiast przejść i powrócić. Same skutki uboczne nie oznaczają również, że Twój kod jest nieczytelny. Nie zyskujesz korzyści z czystego kodu funkcjonalnego . Ale dobrze zrobione, z dobrymi nazwiskami, faktycznie mogą być przyjemne do czytania.
Nie oznacza to, że nie mogą zmienić się w spaghetti jak koszmar. Ale co nie może?
Miłego polowania na kaczki.
źródło