Jaki to wzór i czy powinienem to zrobić?

9

Robię grę w as3 przy użyciu Flash Develop i Flash CS5. Wszystko jest zorientowane obiektowo. Zastanawiałem się, czy powinienem mieć jedną klasę „bramy”, która ma odwołanie do właściwości do wszystkich instancji innych klas, i po prostu przekazuję tę klasę bramy do nowych obiektów, aby miały dostęp do każdej klasy. Tak jak:

 var block:Block = new Block(gateway);

 //In the block class:
 this.gateway.player.setHealth(100);
 //Or:
 this.gateway.input.lock();

Czy to jest jak singleton czy coś takiego? Powinienem to zrobić?

Tetrad
źródło

Odpowiedzi:

13

Jest to tak zwany wzorzec projektowania obiektów kontekstowych i jest lepszy niż wzorzec singletonu.

  • Obiekty kontekstowe pomagają w testowaniu, ponieważ można przekazać fałszywe konteksty do funkcji, które chcesz przetestować. Singletony przeszkadzają, ponieważ aby wyśmiewać singletony, musisz sprawić, by nie były singletonami.
  • Obiekty kontekstowe wyraźnie określają „stan globalny” i dlatego łatwiej jest je uzasadnić. Jeśli funkcja nie przyjmuje obiektu kontekstu, wiesz, że nie używa żadnego globalnego stanu kontekstu. Nie masz takiej gwarancji w przypadku singletonów lub zmiennych globalnych.
  • Obiekty kontekstowe są bardzo nieznacznie wolniejsze, jeśli ich nie używasz, ponieważ dodajesz kolejny parametr do wszystkich wywołań funkcji. Mogą być szybsze niż globale, jeśli ich użyjesz, i prawie zawsze są szybsze niż singletony.
  • Obiekty kontekstowe są łatwiejsze do wdrożenia; zwykle żyją na stosie lub stosie w normalny sposób. Singletony mają skomplikowane problemy z wątkami w wielu językach.

Więc nie, to nie jest singleton, jest o wiele lepszy niż singleton.

Jednak nadal jesteś przechodząc wokół się crapload stanu - fakt jesteś utrzymując wszystko w jednej zmiennej lokalnej czyni go bardziej wyraźne, ale wciąż stwarza poważne conflation obaw . Pamiętaj o jednej zasadzie odpowiedzialności . To ma sens, aby istniał kontekst, który jest właścicielem odtwarzacza i bieżący poziom - są powiązane - ale dlaczego ten sam kontekst posiada klawiaturę?

Rozważ różne poziomy kontekstów, na przykład:

  • GameplayContext - jest właścicielem gracza, wrogów, geometrii poziomu itp.
  • InputContext - posiada uchwyty klawiatury i myszy, zdarzenia wejściowe itp.
  • GraphicsContext - posiada tekstury, uchwyt okna itp.
  • GlobalContext - jest właścicielem GameplayContext, GraphicsContext i InputContext. W tym miejscu chcesz zastosować wzorzec lokalizatora usług , aby w razie potrzeby móc zamienić niektóre konteksty na inne. Być może, w celu szybkiej iteracji i testów, powinna to być prawdziwa zmienna globalna - po prostu zdaj sobie sprawę, że za każdym razem, gdy z niej korzystasz, narastasz dług technologiczny .

Konteksty te nadal w pewnym stopniu łączą obawy - być może jakiś organizator wydarzeń bierze kontekst rozgrywki i naprawdę potrzebuje tylko gracza - ale obowiązki są jasno określone. Wiesz, że coś, co wymaga GameplayContext, nie załaduje tekstury; coś biorąc InputContext nie może zabić gracza.

Społeczność
źródło
+1 Dobra odpowiedź. Niektóre problemy związane z szybkością lub wątkiem tak naprawdę nie mają zastosowania w tym kontekście (ActionScript3 nie obsługuje wątków, a wiele mechanizmów poprawiających prędkość, które działają w C ++, nie mają zastosowania w przypadku używania AS3).
bummzack
Nie wiem dużo o AS3VM, ale w większości dynamicznych języków koszt przekazania / odebrania / używania lokalnego jest wciąż szybszy (wyszukiwanie tablicy) niż koszt wyszukiwania globalnego (wyszukiwanie skrótów) i znacznie szybszy niż wywoływanie funkcji (craploads rzeczy) w celu uzyskania dostępu. Myślę więc, że ta rada nadal obowiązuje.
0

To nie wygląda na wzór Singletona. W moim rozumieniu przekazujesz obiekt z odniesieniami do ważnych obiektów gry do wszystkich swoich instancji.

Jeśli byłby to wzór Singleton, miałbyś:

AudioManager.getInstance().playSound(XY);

Podczas gdy w twoim przypadku możesz mieć:

this.gateway.getAudioManager().playSound(XY);

Wygląda zasadniczo tak samo, ale tak naprawdę nie jest. Jeśli chcesz zastąpić AudioManagernową (rozszerzoną klasą) ExtendedAudioManager, uderzyłbyś w ścianę za pomocą wzoru Singleton. Twoje podejście do bramki poradzi sobie z tym dobrze.

Wadą tego podejścia jest to, że będziesz musiał omijać gatewaywszędzie. Wzór lokalizatora usług (zaproponowany przez Joe Wreschnig w tym wątku), wygląda jak wymiana dobre dla „wzór bramy”.

Czasami lepiej jest po prostu uruchomić prostą i bezpośrednią metodę, niż przeprojektowywać rzeczy. Zwłaszcza, gdy jest to mały projekt lub prototyp. Może mógłbyś stworzyć gatewayjakąś zmienną globalną… np. Game.gatewayi biegnij z tym.

grzmot
źródło
-2

Większość rozwiązań tego problemu, w tym wzorzec Singletona, wymaga użycia zmiennych statycznych. Jeśli kiedykolwiek będziesz mieć tylko jednego gracza, możesz po prostu sprawić, by Player był klasą singleton, co oznacza, że ​​możesz uzyskać dostęp do instancji Player poprzez coś takiego jak Player.currentPlayer. Jednak wiele osób szaleje przeciwko Singletonom. Możesz również mieć ResourceManager lub podobną klasę, która zawiera statyczne odniesienia do różnych przydatnych zmiennych globalnych lub całkiem-zmiennych-globalnych. W twoim kodzie równie dobrze możesz uczynić statycznie dostępnymi zmiennymi „Gatewaya” zamiast pompować kod, rozprowadzając go wszędzie.

Gregory Avery-Weir
źródło
Pytanie znacznie się zmieniło, odkąd udzieliłem tej odpowiedzi, na tyle, że nie warto go edytować.
Gregory Avery-Weir,
2
Poza tytułem w pytaniu nic się nie zmieniło.
bummzack
1
Co? Nic się nie zmieniło poza tytułem. -1
Atakowanie
Myślę, że myślałem o tytule tutaj; Pamiętam, że oryginalny tytuł brzmiał: „Jak mam to zrobić?” Jest całkiem możliwe, że źle odczytałem początkowy tytuł / pytanie, kiedy udzieliłem odpowiedzi.
Gregory Avery-Weir