Строительство синглтон класса - PullRequest
3 голосов
/ 30 апреля 2011

этический вопрос здесь.

Я планирую использовать несколько классов менеджера в моем новом проекте, которые будут выполнять различные задачи по всему проекту.Эти классы являются синглетонами, но требуют построения на основе параметров.

Относительно того, когда и где эта конструкция должна произойти, у меня смешанные чувства.Пока у меня есть эти опции:

Опция A

Легко просто передать эти параметры методу getInstance, имея значение по умолчанию null.При первом вызове будут использоваться параметры, и любые дополнительные вызовы полностью их игнорируют.

Хотя это работает, это выглядит довольно нелогичным по следующим причинам:

  • Это делает документацию неясной. getInstance 'первый параметрдолжно быть типа Collection, но может быть null ... что здесь происходит?Вы можете утверждать, что запись строки об этом в описании прояснит это, но я бы предпочел, чтобы разъяснение было ненужным.

  • Считать ошибочным пропуск getInstanceлюбые параметры конструкции. Это связано с тем, что имя метода не дает явного указания на конструкцию, что делает неясным, что это произойдет.

Опция B

Я думаю о setup методе.Этот метод принимает все параметры, вызывает конструктор класса и изменяет внутреннее состояние класса на initialized.

При вызове метода getInstance до setup он выдаст NotInitializedException.После вызова установки любые дополнительные вызовы setup приведут к PreviouslyInitializedException.

После вызова setup станет доступным getInstance.

Лично этовариант больше нравится мне.Но это кажется чрезмерным.

Какой вариант вы предпочитаете?И почему?

Ответы [ 5 ]

2 голосов
/ 30 апреля 2011

Я, вероятно, попытался бы отказаться от одноэлементного подхода и передать классы менеджера всем, кто в них нуждается.

$manager = new Manager( $collection, $var, $var2 );

$other_class = New OtherClass( $manager );
//or
$other_class = New OtherClass;
$other_class->manager = $manager;
//or
$other_class = New OtherClass;
$other_class->setManager( $manager );
1 голос
/ 30 апреля 2011

Используйте внедрение зависимостей, чтобы передать объект Manager. Не используйте шаблон Singleton. Общепринято, что его использование создает глобальное состояние и делает ваш API обманчивым.

Внедрить экземпляр Manager в любой класс, который нуждается в нем, через конструктор. Каждый класс не должен пытаться создать экземпляр Manager самостоятельно , единственный способ, которым классы получают экземпляр Manager, - это получение его из конструктора.

class NeedsManager
{
    protected $manager;

    public function __construct(Manager $manager)
    {
        $this->manager = $manager;
    }
}

Вам не нужно применять один экземпляр Manager. Только не создавайте его более одного раза. Если все ваши классы, которым нужен экземпляр Manager, получают то, что им нужно от конструктора, и никогда не пытается создать экземпляр самостоятельно , это гарантирует, что в вашем приложении будет только один экземпляр .

0 голосов
/ 30 апреля 2011

Не используйте Singleton, используйте диспетчер ресурсов (или сервисный контейнер, или DI-контейнер):

class ResourceManager
{
    protected static $resource;

    public static function setResource($resource)
    {
        if (!empty(self::$resource)) //resource should not be overwritten
        {
            if ($resource!=self::$resource) return false;
            else return true;
        }

        self::$resource = $resource;
        return true;
    }

    public static function getResource()
    {
        return self::$resource;
    }
}

Resource Manager позволяет вам устанавливать любые пользовательские классы для модульного тестирования (например, внедрение зависимостей), вы можете просто получить необходимые ресурсы, не запрашивая их в конструкторе (мне нравится DI, но иногда просто удобнее использовать пустые конструкторы).

Готовый вариант: http://symfony.com/doc/current/book/service_container.html (мне не нравится перемещать логику из кода в конфиги, но в автономном модуле это выглядит приемлемо).

0 голосов
/ 30 апреля 2011

Вы смотрите на использование шаблона проектирования фабрики. Фабрики - это объекты, которые действуют как причудливые конструкторы для других объектов. В вашем случае вы перенесете настройки и получите экземпляр на завод. Статья в вики довольно хороша - http://en.wikipedia.org/wiki/Factory_method_pattern

class SingletonFoo {
  //properties, etc
    static $singleton = NULL;
    private function __constructor(){}
    static function getInstance(){
        if(NULL === self::$singleton) {
            self::$singleton = new SingletonFoo();
        }
        return self::$singleton;
    }
}

class FooFactory {
    static $SingletonFoo = null;
    static function setup($args){
        if( !(NULL === self::$SingletonFoo)){
            throw new AlreadyInstantiatedException();
        }
        self::$SingletonFoo = SingletonFoo::getInstance();
        //Do stuff with $args to build SingletonFoo
        return self::$SingletonFoo;
    }

    static function getInstance(){
        if(NULL === self::$SingletonFoo) {
            throw new NotInstantiatedException();
        }
        return self::$SingletonFoo;
    }
}
0 голосов
/ 30 апреля 2011

Как насчет варианта 3. Если они являются настоящими синглетонами, настройте файлы свойств для их параметров для использования с get-экземпляром без аргументов.

Если это не подходит, возможно, вы неправильно используете шаблон синглтона.

...