Блокировка возможности создания классов напрямую в обход фабрики - PullRequest
5 голосов
/ 27 марта 2011

В базовом классе для всех моделей в нашей системе MVC я создал фабричный метод BaseCLass :: getNew (), который возвращает экземпляр запрошенного дочернего класса при вызове через SomeChildClass :: getNew ().

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

 new SomeChildClass

выдаст исключение при создании, и будут использоваться только классы, созданные фабрикой.

Есть идеи, как этого достичь?

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

edit: я не могу сделать свой конструктор приватным, так как конструктор фреймворка в классе, который я наследую, является публичным, и php не позволил бы мне это.

Ответы [ 4 ]

2 голосов
/ 27 марта 2011

Путем создания конструктора дочернего класса protected.Родительский класс будет иметь доступ ко всем защищенным методам дочернего элемента.Любая попытка напрямую создать дочерний объект (т. Е. new child) приведет к фатальной ошибке.

<?php

class factory
{

    static public function create()
    {
        return new child;
    }

}

class child extends factory
{

    protected function __construct()
    {
        echo 'Ok';
    }

}

$c = factory::create(); // Ok
$c2 = new child; // fatal error

?>

Хотя этот метод не позволяет вместо этого выдавать исключение: (

Еслитогда абсолютно необходимо, на ум приходит только функция debug_backtrace () (помимо использования синглтона для самого дочернего элемента или принудительного использования шаблонов пула объектов с использованием и передачи идентификаторов GUID, сгенерированных фабрикой и проверенных дочерним элементом).посмотрите на 2-е значение массива, чтобы убедиться, что "function" === "create" и "class" === "фабрика. Выдает исключение, если не совпадает. Сначала я не предлагал это, только потому, что подозреваю, что использую debug_backtraceможет дать удар по производительности.

1 голос
/ 27 марта 2011

Предоставляя классу собственный конструктор .

Обновление - решение, которое соответствует вашим заявленным требованиям

class Base {
    private static $constructorToken = null;

    protected static function getConstructorToken() {
        if (self::$constructorToken === null) {
            self::$constructorToken = new stdClass;
        }

        return self::$constructorToken;
    }
}

class Derived extends Base {
    public function __construct($token) {
        if ($token !== parent::getConstructorToken()) {
            die ("Attempted to construct manually");
        }
    }

    public static function makeMeOne() {
        return new Derived(parent::getConstructorToken());
    }
}

Это решение использует преимущества равенства объектовправила для stdClass, хранящие в базовом классе объект «магический пароль», к которому могут обращаться только производные классы.Вы можете настроить его по вкусу.

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

0 голосов
/ 27 марта 2011

есть несколько способов реализовать это

  • сделать родительский класс закрытым для использования magic
  • user magic function __autoload;проверить тип класса и через ошибку с недопустимым сообщением

http://php.net/manual/en/function.is-a.php

0 голосов
/ 27 марта 2011

Объявите конструктор класса закрытым, и он может быть вызван только из собственных методов класса, таких как getNew().

...