To całkiem proste:
Zamiast mieć Konstruktora, który wykonuje konfigurację,
// c-family pseudo-code
public class Thing {
public Thing (a, b, c, d) { this.x = a; this.y = b; /* ... */ }
}
... niech twój konstruktor zrobi niewiele lub nic, i napisze metodę o nazwie .init
lub .initialize
, która zrobiłaby to, co normalnie zrobiłby twój konstruktor.
public class Thing {
public Thing () {}
public void initialize (a, b, c, d) {
this.x = a; /*...*/
}
}
Więc teraz zamiast po prostu:
Thing thing = new Thing(1, 2, 3, 4);
Możesz iść:
Thing thing = new Thing();
thing.doSomething();
thing.bind_events(evt_1, evt_2);
thing.initialize(1, 2, 3, 4);
Zaletą jest to, że możesz teraz łatwiej używać systemów wstrzykiwania zależności / inwersji kontroli w swoich systemach.
Zamiast mówić
public class Soldier {
private Weapon weapon;
public Soldier (name, x, y) {
this.weapon = new Weapon();
}
}
Można budować żołnierza, dać mu metodę zasilania, korzystny gdzie ręką mu broń, a następnie wezwać wszystkich pozostałych funkcji konstruktora.
Więc teraz zamiast podklasować wrogów, w których jeden żołnierz ma pistolet, a drugi ma karabin, a drugi ma strzelbę, a to jedyna różnica, możesz po prostu powiedzieć:
Soldier soldier1 = new Soldier(),
soldier2 = new Soldier(),
soldier3 = new Soldier();
soldier1.equip(new Pistol());
soldier2.equip(new Rifle());
soldier3.equip(new Shotgun());
soldier1.initialize("Bob", 32, 48);
soldier2.initialize("Doug", 57, 200);
soldier3.initialize("Mike", 92, 30);
To samo dotyczy zniszczenia. Jeśli masz specjalne potrzeby (usuwanie detektorów zdarzeń, usuwanie instancji z tablic / dowolnych struktur, z którymi pracujesz itp.), Wówczas ręcznie je wywołujesz, abyś dokładnie wiedział, kiedy i gdzie w programie się dzieje.
EDYTOWAĆ
Jak zauważył Kryotan poniżej, odpowiada to na „How” oryginalnego postu , ale tak naprawdę nie działa dobrze na „dlaczego”.
Jak zapewne widać w powyższej odpowiedzi, różnica między:
var myObj = new Object();
myObj.setPrecondition(1);
myObj.setOtherPrecondition(2);
myObj.init();
i pisanie
var myObj = new Object(1,2);
mając po prostu większą funkcję konstruktora.
Trzeba argumentować za obiektami, które mają 15 lub 20 warunków wstępnych, co spowodowałoby, że konstruktor byłby bardzo, bardzo trudny w obsłudze, a także ułatwiłby widzenie i zapamiętywanie, wyciągając te rzeczy do interfejsu , dzięki czemu można zobaczyć, jak działa tworzenie instancji, o jeden poziom wyżej.
Opcjonalna konfiguracja obiektów jest naturalnym rozszerzeniem tego; opcjonalnie ustawiając wartości w interfejsie, przed uruchomieniem obiektu.
JS ma kilka świetnych skrótów do tego pomysłu, które wydają się nie na miejscu w silniejszych językach typu C.
To powiedziawszy, istnieje szansa, że jeśli masz do czynienia z listą argumentów, która jest długa w twoim konstruktorze, twój obiekt jest zbyt duży i robi zbyt wiele, jak jest. Ponownie, jest to kwestia preferencji osobistych i istnieją daleko idące wyjątki, ale jeśli przenosisz 20 przedmiotów do obiektu, są duże szanse, że możesz znaleźć sposób, aby ten obiekt zrobił mniej, tworząc mniejsze obiekty .
Bardziej stosownym powodem i jednym z powszechnie stosowanych jest to, że inicjalizacja obiektu opiera się na danych asynchronicznych, których obecnie nie masz.
Wiesz, że potrzebujesz obiektu, więc i tak go utworzysz, ale aby poprawnie działać, potrzebuje danych z serwera lub z innego pliku, który teraz musi załadować.
Znowu, czy przekazujesz potrzebne dane do gigantycznej inicjacji, czy budujesz interfejs, nie jest tak naprawdę ważny dla tej koncepcji, tak bardzo jak dla interfejsu twojego obiektu i projektu twojego systemu ...
Ale jeśli chodzi o budowę obiektu, możesz zrobić coś takiego:
var obj_w_async_dependencies = new Object();
async_loader.load(obj_w_async_dependencies.async_data, obj_w_async_dependencies);
async_loader
może otrzymać nazwę pliku, nazwę zasobu lub cokolwiek innego, załadować ten zasób - może ładuje pliki dźwiękowe lub dane obrazu, a może ładuje zapisane statystyki postaci ...
... a następnie zasiliłby te dane z powrotem obj_w_async_dependencies.init(result);
.
Ten rodzaj dynamiki znajduje się często w aplikacjach internetowych.
Niekoniecznie w konstrukcji obiektu, dla aplikacji wyższego poziomu: na przykład galerie mogą od razu się załadować i zainicjować, a następnie wyświetlać zdjęcia podczas przesyłania strumieniowego - to nie jest tak naprawdę inicjalizacja asynchroniczna, ale tam, gdzie jest ona widziana częściej, w bibliotekach JavaScript.
Jeden moduł może zależeć od drugiego, dlatego inicjalizacja tego modułu może zostać odroczona do czasu zakończenia ładowania osób zależnych.
Jeśli chodzi o przypadki tego specyficzne dla gry, rozważ rzeczywistą Game
klasę.
Dlaczego nie możemy wywołać .start
lub .run
w konstruktorze?
Zasoby muszą zostać załadowane - reszta wszystkiego została właściwie zdefiniowana i dobrze jest przejść, ale jeśli spróbujemy uruchomić grę bez połączenia z bazą danych lub bez tekstur, modeli, dźwięków lub poziomów, nie będzie szczególnie interesująca gra ...
... więc jaka jest różnica między tym, co widzimy w typowym Game
, z wyjątkiem tego, że nadajemy jego metodzie „kontynuuj” nazwę, która jest bardziej interesująca niż .init
(lub odwrotnie, jeszcze bardziej rozbijać inicjalizację, aby oddzielić ładowanie, konfigurowanie rzeczy, które zostały załadowane i uruchamianie programu, gdy wszystko zostało skonfigurowane).