14

我在另一个问题上看到了这段代码 - 第二个答案链接,第一条评论是它是一个静态工厂反模式并且它违反了 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

4 回答 4

10

不,这不是反模式。就个人而言,每当我看到“反模式”这个词时,我都会持保留态度。那些不喜欢你的代码但又无法真正阐明原因的人很容易把它扔掉。

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

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

于 2013-01-24T15:43:36.627 回答
2

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

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

如果您在工厂中有数据访问代码,只要该代码在一个单独的类中(在应用程序中重复使用以进行数据访问)并且您只需调用它,我仍然可以(不太好,但仍然可以)得到你需要的东西。在这种情况下,它将是两种模式的组合,工厂和外观。

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

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

于 2013-01-24T15:44:07.830 回答
0

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

$classname='User';

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

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

于 2014-09-14T12:50:23.433 回答
-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();
于 2014-05-10T12:32:26.100 回答