post_ico4

Wzorce projektowe, cz. 1 Singleton

Tym postem rozpoczynam kolejny cykl postów – tym razem o wzorcach projektowych przydatnych w projektowaniu i programowaniu aplikacji webowych. Na początek opiszę jeden z najprostszych, a zarazem dość popularny wzorzec – Singleton.

Singleton jest jednym z najprostszych wzorców projektowych. Jego celem jest ograniczenie możliwości tworzenia obiektów danej klasy do jednej instancji oraz zapewnienie globalnego dostępu do stworzonego obiektu – jest to obiektowa alternatywa dla zmiennych globalnych.


Diagram klasy wzorca Singleton

Singleton implementuje się poprzez stworzenie klasy, która posiada statyczną metodę getInstance(). Metoda ta sprawdza, czy istnieje już instancja tej klasy, jeżeli nie – tworzy ją i przechowuje jej referencję w prywatnym polu. Aby uniemożliwić tworzenie dodatkowych instancji, konstruktor klasy deklaruje się jako prywatny lub chroniony.

Przykładowa implementacja

<?php
class Singleton {
    private static $instance;
    private function __construct() {}
    private function __clone() {}
    public static function getInstance() {
        if(self::$instance === null) {
            self::$instance = new Singleton();
        }
        return self::$instance;
    }
}
$singleton = Singleton::getInstance();
?>

Przykład z życia wzięty

Rozważmy klasę zawierającą konfigurację aplikacji.

<?php
class Config {
    private static $instance;
    private $config = array(
        "login"     =>  "mojlogin",
        "password"  =>  "haslo",
        "language"  =>  "pl"
        );

    private function __construct() {}
    private function __clone() {}

    public static function getInstance() {
        if(self::$instance === null) {
            self::$instance = new Config();
        }
        return self::$instance;
    }
    public function setLanguage($lang) {
        $this->config["language"] = $lang;
    }
    public function getLanguage() {
        return $this->config["language"];
    }
}

// testy
$conf1 = Config::getInstance();
echo $conf1->getLanguage(); // wyswietla "pl"
$conf2 = Config::getInstance();
$conf2->setLanguage("en");
echo $conf1->getLanguage(); // wyswietla "en"
?>

Klasa Config zawiera tablicę z podstawowymi ustawieniami aplikacji. Dzięki zastosowaniu Singletona zmiana ustawień w jednym miejscu (np. zmiana języka na stronie przez użytkownika) jest „widoczna” w każdym miejscu aplikacji. Ponadto można łatwo zaprojektować klasę z konfiguracją, tak by było można łatwo dodawać kolejne ustawienia w miarę potrzeb.

Zalety i wady

Zalety:

  • Pobieranie instancji klasy jest niewidoczne dla użytkownika. Nie musi on wiedzieć, czy w chwili wywołania metody instancja istnieje czy dopiero jest tworzona.
  • Tworzenie nowej instancji zachodzi dopiero przy pierwszej próbie użycia.
  • Klasa zaimplementowana z użyciem wzorca singleton może samodzielnie kontrolować liczbę swoich instancji istniejących w aplikacji.

Wady:

  • Brak elastyczności, ponieważ już na poziomie kodu, na „sztywno” określana jest liczba instancji klasy.
  • Utrudnia testowanie i usuwanie błędów w aplikacji.

Zastosowanie

Programując w PHP używa się wzorca Singleton do przechowywania konfiguracji aplikacji oraz utrzymania połączenia z bazą danych. Jednak, warto pamiętać o wadach tego wzorca i korzystać z niego rozważnie. Zbyt częste stosowanie wzorca Singleton pogarsza przejrzystość kodu.

Powiązane tematy

Co sądzisz o wpisie?
BeżnadziejnySłabyŚredniDobryBardzo dobry (2 głosów, średnia ocen: 3,00 z 5)
Loading...
  • autor

    Dzięki, przyda się! :)

  • moss

    Dzięki!

    Fajnie było by jeszcze dołączyc chociaż jeden praktycznie działający przykład wykorzystania:)

  • Adam Wójs

    Komentarz do linii 4 w przykładowej implementacji: Nie publiczny tylko prywatny konstruktor ;-)

  • Nie będę rozpoczynał dyskusji starej jak świat nt. tego, czy (i dlaczego nie:) powinno się stosować Singleton.

    Niemniej jednak brakuje, jak dla mnie, w Twoim poście, przykładu, gdzie warto go zastosować, jakaś z życia wzięta sytuacja. Bez tego, jest on (post) jedynie kolejną definicją wzorca, których w sieci wiele.

  • Ok, dziś lub jutro dodam jakiś prosty przykład (w kolejnych częściach też będę dawać jakiś przykład po teoretycznym wstępie).

    @Sebastian ta dyskusja jest wieczna :P Odpowiednio wykorzystany Singleton przydaje się, ale tak jak napisałem na końcu, trzeba rozważnie z niego korzystać.

    EDIT:
    Przykład dodany

  • moss

    Dzięki za dodanie przykładu :)

  • @admin nie przydaje się:) Odkąd projektuje rozwiązania nie zdarzyło mi się nigdy wykorzystać tego wzorca:) Nie dlatego, że go nie lubię, po prostu nie był nigdy potrzebny.

    Odpowiednie zależności i odpowiedzialności obiektów prowadzą do tego, że singleton nie jest Ci potrzebny.

  • Janko

    Sebastian, nas interesuje wzorzec, a nie jałowe dyskusje ludzi, którzy nie mają co robić albo cierpią na przerost ego i godzinami drążą proste tematy. Komu potrzebny, ten skorzysta, a hejterzy w rodzaju „a moje projekty są cool i ja nie muszę z tego korzystać” niech zajmą się czymś pożyteczniejszym.

    Zastosowanie: obiekt sesji, współdzielony słownik.

  • Robert

    Singleton to właściwie antywzorzec

  • Witam, prośba o pomoc.

    Mam taką kasę dla singletona.

    Dlaczego nie mogę w getInstance() zrobić czegoś takiego self::$_instance->query(‚Select 1’);
    ?

    Info w komentarzach, 7 i 15 linijki kodu.

    class DataBase {
    public static $_instance = null;
    private function __clone(){}
    private function __construct() {
    $dns = ‚mysql:host=’ . DB_HOST . ‚;dbname=’ . DB_NAME . ‚;charset=’ . DB_CHARSET;
    $conn = new PDO($dns,DB_USER,DB_PASSW);
    // a tutaj moge $conn->query(‚Select 1’);
    return $conn;
    }

    public static function getInstance() {
    if(!(self::$_instance instanceof DataBase)) {
    self::$_instance = new DataBase();
    }
    // dlaczego nie mogę self::$_instance->query(‚Select 1’);
    return self::$_instance;
    }