Является ли мой factory анти-шаблон?

Я видел этот код по другому вопросу - второй ответ link, и первым комментарием было то, что он является статическим factory анти-шаблоном и что он нарушает SRP

class User {
    public static function create($userid) {
        // get user from the database

        // set $isPartner to true or false
        // set $isClient to true or false
        // set $isModerator to true or false

        if ($isPartner) {
            return new Partner($userid);
        } elseif ($isClient) {
            return new Client($userid);
        } elseif ($isModerator) {
            return new Moderator($userid);
        } else {
            return new User($userid);
        }
    }
}

$person = User::create($userid);

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

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

class DatabaseClass()
{
...deals with getting a result from the database...
}

abstract class User()
{
...base class for all users...
}

class AdminUser extends User(){}
class StaffUser extends User(){}
class BasicUser extends User(){}

class UserFactory()
{
    function createUser($privilege)
    {
        if($privilege=="high")
            return new AdminUser($privilege);
        else if($privilege=="med")
            return new StaffUser($privilege);
        else
            return new BasicUser($privilege);
    }

$db=new DatabaseClass($username,$password);
$result=$db->getUser();
$userfactory=new UserFactory();
$user=$userfactory->createUser($result);

Теперь на данный момент я не использую статический метод, но мой oop все равно будет рассматриваться как анти-шаблон?

Тем более, что на самом деле я не вижу никакой разницы в том, чтобы делать что-то вроде этого, и это примерно одно и то же:

$result=DatabaseClass::getUser($username,$password);
$user=UserFactory::createUser($result);

Ответ 1

Нет, это не анти-шаблон. Лично я воспринимаю термин "анти-шаблон" с зерном соли всякий раз, когда вижу это. Это слишком легко подбрасывается людьми, которые не любят ваш код, но не могут действительно объяснить, почему.

Проблема со статическим factory заключается в том, что любой класс, который использует factory, должен явно зависеть от него. Это нарушает принцип, согласно которому мы должны зависеть от абстракций, а не от конкреций ( "D" в SOLID). Это делает код с помощью factory более сложным для повторного использования и unit test. Но имейте в виду, что этот подход также имеет свои преимущества. Это легче писать и легче понять.

Ваш код эквивалентен статическому методу factory. Проблема в обоих случаях заключается в том, что вызывающий должен знать конкретный класс factory.

Ответ 2

Ваш factory не является проблемой, является ли связь с db, я думаю. Кроме этого, вы хорошо используете метод factory.

После просмотра редактирования его наилучшим образом отделите доступ к данным из factory. Это не столько "анти-шаблон", сколько плохая идея с точки зрения обслуживания.

Я бы все-таки был в порядке (не так хорошо, но все еще хорошо), если у вас был код доступа к данным внутри factory, если этот код был в отдельном классе (который повторно используется в приложении для доступа к данным) и вы просто называете это, чтобы получить то, что вам нужно. В этом случае это будет комбинация двух шаблонов: factory и фасад.

То, что я действительно заплатил, заключается в том, чтобы выяснить, не изменится ли информация во время сеанса, если это так просто пойти один раз в db, сохранить результаты. Если вы только однажды создадите Пользователь (или производные классы), сделайте damm уверенным, что вы делаете это только один раз.

То, что я думаю, более важно, чтобы слепое соблюдение шаблонов.

Ответ 3

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

$classname='User';

$Object=new $classname; //instantiates new User()

Этот код создает экземпляр класса, имя которого хранится в переменной $classname.

Ответ 4

Я не так хорошо с шаблоном Factory, однако, если вы хотите получить какую-то выгоду, он может абстрагировать создание, основанное на вариации настойчивости, например. если он адаптирует базу данных для пользователей или нет.

class DatabaseUserFactory implements UserFactory
{
    private $dbClass;

    function __construct(DatabaseClass $dbClass)
    {
        $this->dbClass = $dbClass;
    }

    /**
     * @return user
     */
    function createUser()
    {
        $result = $db->getUser();
        return $this->createUserByPrivilege($result->getPrivilege());

    }

    private function createUserByPrivilege($privilege)
    {
        if ($privilege == "high")
            return new AdminUser($privilege);
        else if ($privilege == "med")
            return new StaffUser($privilege);
        else
            return new BasicUser($privilege);
    }
}

$db          = new DatabaseClass($username, $password);
$userfactory = new DatabaseUserFactory($db);

// ...

$user = $userfactory->createUser();