Poniższa odpowiedź jest błędna, ale zatrzymam ją, aby inni mogli się z niej uczyć (patrz poniżej)
W ExampleAmożna użyć tego samego Configwystąpienia w wielu klasach. Jeśli jednak Configw całej aplikacji powinna znajdować się tylko jedna instancja, rozważ zastosowanie wzorca Singleton, Configaby uniknąć wielu instancji Config. A jeśli Configjest singletonem, możesz zamiast tego wykonać następujące czynności:
class ExampleA
{
private $config;
public function __construct()
{
$this->config = Config->getInstance();
}
}
$exampleA = new ExampleA();
Z ExampleBdrugiej strony, zawsze otrzymasz osobne wystąpienie Configdla każdego wystąpienia ExampleB.
Która wersja powinna zostać zastosowana, zależy od tego, jak aplikacja będzie obsługiwać wystąpienia Config:
- jeśli każda instancja
ExampleXpowinna mieć osobną instancję Config, idź z ExampleB;
- jeśli każde wystąpienie
ExampleXbędzie dzielić jedno (i tylko jedno) wystąpienie Config, użyj ExampleA with Config Singleton;
- jeśli instancje
ExampleXmogą używać różnych instancji Config, trzymaj się ExampleA.
Dlaczego przejście Configna Singleton jest złe:
Muszę przyznać, że wczoraj dowiedziałem się o wzorze Singleton (czytając książkę wzorców projektowych Head First ). Naiwnie poszedłem i zastosowałem go w tym przykładzie, ale jak wielu zauważyło, jeden sposób jest inny (niektórzy byli bardziej tajemniczy i mówili tylko „robisz to źle!”), To nie jest dobry pomysł. Tak więc, aby inni nie popełnili tego samego błędu, który właśnie popełniłem, poniżej znajduje się podsumowanie, dlaczego wzorzec Singleton może być szkodliwy (na podstawie komentarzy i tego, co go znalazłem w Google):
Jeśli ExampleApobierze własne odwołanie do Configinstancji, klasy będą ściśle powiązane. Nie będzie ExampleAmożliwości użycia innej wersji Config(powiedzmy podklasy). Jest to okropne, jeśli chcesz przetestować ExampleAprzy użyciu instancji makiety, Configponieważ nie ma sposobu, aby to zrobić ExampleA.
Założeniem będzie jeden i tylko jeden przypadek, który Configmoże się teraz utrzymywać , ale nie zawsze możesz być pewien, że to samo będzie obowiązywać w przyszłości . Jeśli w pewnym momencie okaże się, że Configpożądanych będzie wiele instancji , nie ma możliwości osiągnięcia tego bez przepisania kodu.
Chociaż jedno i jedyne wystąpienie Configmoże być prawdą przez całą wieczność, może się zdarzyć, że będziesz chciał móc skorzystać z jakiejś podklasy Config(wciąż mając tylko jedno wystąpienie). Ale, ponieważ kod pobiera bezpośrednio poprzez wystąpienie getInstance()o Config, który jest staticmetoda, nie ma sposobu, aby uzyskać podklasy. Ponownie kod musi zostać przepisany.
Fakt, że ExampleAzastosowania Configzostaną ukryte, przynajmniej podczas przeglądania interfejsu API ExampleA. Może to być, ale nie musi, zła rzecz, ale osobiście uważam, że jest to niekorzystne; na przykład, utrzymując, nie ma prostego sposobu, aby dowiedzieć się, na które klasy będą miały wpływ zmiany, Configbez patrzenia na implementację każdej innej klasy.
Nawet jeśli fakt, że ExampleAużywa się Singletona Config , sam w sobie nie stanowi problemu, może on stać się problemem z testowego punktu widzenia. Obiekty Singleton będą nosić stan, który będzie trwał do momentu zakończenia aplikacji. Może to stanowić problem podczas uruchamiania testów jednostkowych, ponieważ chcesz, aby jeden test był izolowany od drugiego (tj. Że wykonanie jednego testu nie powinno wpływać na wynik innego). Aby to naprawić, obiekt Singleton musi zostać zniszczony między każdym uruchomieniem testowym (potencjalnie konieczne ponowne uruchomienie całej aplikacji), co może być czasochłonne (nie wspominając o żmudnych i irytujących).
Powiedziawszy to, cieszę się, że popełniłem ten błąd tutaj, a nie podczas wdrażania prawdziwej aplikacji. W rzeczywistości zastanawiałem się nad przepisaniem mojego najnowszego kodu w celu użycia wzorca Singleton dla niektórych klas. Chociaż mógłbym z łatwością cofnąć zmiany (oczywiście wszystko jest przechowywane w SVN), nadal zmarnowałbym czas na robienie tego.