我的工厂是反模式吗?

时间:2013-01-24 15:14:33

标签: php oop

我在另一个问题上看到了这个代码 - 第二个答案link,第一个评论是它是一个静态的工厂反模式,它违反了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);

4 个答案:

答案 0 :(得分:8)

不,这不是反模式。就个人而言,每当我看到它时,我都会用一粒盐“反模式”这个词。很容易被那些不喜欢你的代码而却无法清楚表达原因的人抛弃。

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

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

答案 1 :(得分:1)

你的工厂不是问题,我猜的是对db的连接。 除此之外,您正在使用工厂方法。

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

如果您在工厂内部拥有数据访问代码,只要该代码位于单独的类中(在应用程序中重复用于数据访问),我仍然可以(不太好但仍然可以)叫它来得到你需要的东西。在这种情况下,它是两种模式的组合,工厂和立面。

我真正关注的是在会话期间查明数据是否会发生变化,如果是这样,只需去一次数据库就可以保留结果。如果您只创建一次User(或派生类),请确保您只执行一次。

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

答案 2 :(得分:0)

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

$classname='User';

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

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

答案 3 :(得分:-2)

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

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