Php 我的工厂是反模式的吗?

Php 我的工厂是反模式的吗?,php,oop,Php,Oop,我在另一个问题-第二个答案上看到了这段代码,第一条评论是这是一个静态工厂反模式,它违反了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 $isM

我在另一个问题-第二个答案上看到了这段代码,第一条评论是这是一个静态工厂反模式,它违反了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——因为它处理连接到数据库以及构建新类的问题,但除此之外,我不确定我是否理解为什么它是一个反模式

我想写一些与此非常相似的代码,所以我现在想知道是否要避免它,这是我的代码(伪代码):

现在我没有使用静态方法,但是我的oop仍然会被认为是反模式吗

特别是因为我真的看不出这样做有什么区别,而且几乎是一样的:

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

不,这不是反模式。就我个人而言,每当我看到“反模式”这个词时,我都会对它持保留态度。它太容易被不喜欢你的代码但却无法真正阐明原因的人抛出

静态工厂的问题是,任何使用工厂的类都必须显式依赖于它。这违反了我们应该依赖抽象而不是具体的原则(固体中的“D”)。这使得使用工厂的代码更难重用和单元测试。但请记住,这种方法也有好处。它更容易写,也更容易理解


您的代码相当于静态工厂方法。这两种情况下的问题都是调用者必须知道工厂的具体类。

我想,工厂不是问题所在,而是与数据库的连接。 除此之外,您还很好地使用了工厂方法

看到编辑后,最好将数据访问与工厂分离。 从维护的角度来看,这与其说是一个“反模式”,不如说是一个坏主意

如果您在工厂中有数据访问代码,只要该代码在一个单独的类中(可在整个应用程序中重用以进行数据访问),并且您只需调用它以获取所需的内容,那么我仍然可以(不是很好,但仍然可以)。在这种情况下,它将是两种模式的组合,一个工厂和一个门面

我真正要注意的是找出数据在会话期间是否不会改变,如果是这样,只需到数据库保存一次结果。如果只创建一次用户(或派生类),请确保只创建一次


我认为盲目尊重模式更重要。

我不太喜欢工厂模式,但是,如果你想获得一些好处,它可以基于持久性变化抽象创建,例如,它是否为用户调整数据库

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();

PHP具有动态类实例化功能,其中应该实例化的类名可以是变量。以下代码可以正常工作:

$classname='User';

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

此代码实例化了名称存储在$classname变量中的类。

能否添加指向其他问题的链接?将链接添加到我问题的开头。我给出的代码示例是OP遇到的问题的第二个答案,批评是在被接受的答案海报上写的评论中。因此,如果我使用我编写的代码,是否最好先实例化每个类,然后调用该方法,而不是用我的快捷方式处理静态?我不太明白为什么它依赖于工厂,如果我们谈论的是能够单独测试每个类以确保其方法工作,我可以实例化该类并给出它的依赖项,而不需要工厂。。?有没有更好的方法来编写它,使它不依赖于工厂?我无法想象用户不需要知道具体的工厂类,问题在于测试使用工厂的代码。例如,行
$userfactory=newuserfactory(),创建对UserFactory类的具体依赖关系。如果您对此没有意见(实际上只有您可以判断它是否可以接受),那么您可以使用静态或实例方法。这没什么区别。只需在代码库中保持一致。了解工厂的具体类的方法是将抽象工厂接口传递给使用者类。这就是所谓的依赖注入。如果您还没有在代码库中使用它,那么添加它将非常困难。我怀疑这是否值得。这是有道理的,我很高兴我没有完全走错方向,但如果可能的话,我非常希望坚持依赖注入。我不明白你说的“传入抽象工厂接口”是什么意思,接口只是其他类遵循的蓝图?我将不得不研究它,但是你知道“传递抽象工厂接口”的好例子吗?是的。在您的情况下,UserFactory类将在其构造函数中接受某种DB访问接口。
$classname='User';

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