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