22 Stimmen

Abstrakte Singleton-Klasse erweitern

Wenn Sie eine Fabrikklasse haben, die neue Objekte irgendeiner Art erstellt, und diese Faktorklasse ist ein Singleton, wie dies:

class Database_Factory extends Base_Factory {
    private static $factory;
    private $objects = array();

    public function __get($profile) {
        // check for object and return it if it's created before
    }

    public static function getInstance(){
        if (!self::$factory)
            self::$factory = new self();
        return self::$factory;
    }
}

Derselbe Code wird immer dann wiederholt, wenn ein Objekt eine eigene Fabrik benötigt. Also habe ich beschlossen, diese Fabrikklasse abstrakt zu machen und nur spezifische Routinen für jede Fabrik zu implementieren. Aber PHP erlaubt es nicht, eine abstrakte Klasse zu instanziieren.

abstract class Base_Factory {
    public static function getInstance(){
        if (!self::$factory)
            self::$factory = new self();
        return self::$factory;
    }
}

Schwerwiegender Fehler: Die abstrakte Klasse Base_Factory kann nicht instanziiert werden

Was würden Sie tun?

42voto

Ferdinand Beyer Punkte 61121

In PHP-Methoden, self bezieht sich immer auf die Klasse, in der die Methode definiert ist. Seit Version 5.3.0 unterstützt PHP die "späte statische Bindung", bei der Sie die static Schlüsselwort, um auf überschriebene statische Methoden zuzugreifen, sowie auf die Funktion get_called_class() um den Namen der abgeleiteten Klasse im statischen Kontext zu erhalten.

Ihr Entwurf hat jedoch einen großen Fehler: Die statische Eigenschaft $factory definiert in Base_Factory wird von allen abgeleiteten Klassen gemeinsam genutzt. Daher werden beim ersten Mal, wenn ein Singleton erstellt und in dieser Eigenschaft gespeichert wird, alle weiteren Aufrufe von getInstance() wird dasselbe Objekt zurückgeben, unabhängig davon, welche abgeleitete Klasse verwendet wird.

Sie könnten ein statisches Wörterbuch verwenden, das Klassennamen auf Singleton-Objekte abbildet:

abstract class Base_Factory {
    private static $_instances = array();
    public static function getInstance() {
        $class = get_called_class();
        if (!isset(self::$_instances[$class])) {
            self::$_instances[$class] = new $class();
        }
        return self::$_instances[$class];
    }
}

Ach ja, noch etwas: Die Tatsache, dass Sie nach einer Möglichkeit suchen, Code für Singleton-Objekte wiederzuverwenden, könnte ein Hinweis darauf sein, dass Sie das Singleton-Entwurfsmuster übermäßig nutzen! Fragen Sie sich, ob die Klassen, die Sie als Singletons implementieren wollen, wirklich Singletons sind und ob es keinen Anwendungsfall gibt, in dem Sie mehrere Instanzen der jeweiligen Klasse benötigen.

Oft ist es viel besser, nur ein Singleton zu verwenden, das den aktuellen "Anwendungskontext" repräsentiert und Zugriffsmöglichkeiten für Objekte bietet, die Singletons in Bezug auf diesen Kontext sind.

10voto

PHP 5.3+

abstract class Singleton
{
    /**
     * Instance
     *
     * @var Singleton
     */
    protected static $_instance;

    /**
     * Constructor
     *
     * @return void
     */
    protected function __construct() {}

    /**
     * Get instance
     *
     * @return Singleton
     */
    public final static function getInstance() {
        if (null === static::$_instance) {
            static::$_instance = new static();
        }

        return static::$_instance;
    }
}

3voto

Lukman Punkte 17776

Nur PHP >= 5.3

abstract class Base_Factory {
    protected static $factory;
    public static function getInstance(){
        if (!self::$factory) {
            $class = get_called_class();
            self::$factory = new $class();
        }
        return self::$factory;
    }
}

1voto

Peter Lindqvist Punkte 9942

Registrieren Sie Ihre Singletons in einer einfachen Klasse wie dieser

class Singletons {
    static private $singleton = array();
    public function getSingleton($class) {
    if (!isset(self::$singleton[$class])) {
        self::$singleton[$class] = new $class;
    }
    return self::$singleton[$class];
    }
}

Dann tun Sie dies

class aSingleton {
    public $i;
    public function test() {
    ++$this->i;
    echo get_class() . " called {$this->i} times\n";
    }
}

Singletons::getSingleton('aSingleton')->test();
Singletons::getSingleton('aSingleton')->test();

Ausgabe

aSingleton called 1 times
aSingleton called 2 times

-1voto

Emre Yazici Punkte 9938

Per Definition können abstrakte Klassen in PHP nicht instanziiert werden wie in anderen objektorientierten Sprachen. Ihre Base_Factory sollte also eine Schnittstelle statt einer abstrakten Klasse sein.

Aus dem PHP-Handbuch: "Es ist nicht erlaubt, eine Instanz einer Klasse zu erstellen, die als abstrakt definiert wurde."

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X