[英]How to implement factory design pattern
我正在尝试将工厂设计模式应用于应用程序中的实际问题。 我正在使用数据对象(有点像ORM,但不完全是),其中一个对象代表数据库中的一行,其属性为列。 话虽如此-我有3种不同类型的用户,它们都扩展了基类User
,并且都保存在同一users
数据库表中。 我还有一个用于确定用户type
的额外列type
。
因此,要获取ID为1的用户,我将使用以下代码:
$user = User::getByPK(1);
但是,不同类型的用户具有不同的属性和方法,我需要获取适当的实例,这就是我遇到的问题。 我创建了一个工厂类,但是我不确定如何调用它。 在确定用户类型之前,我需要从数据库中获取有关该用户的信息,但是我需要实例化适当的类,并且这两件事相互依赖。
这就是我所做的-我得到了适当的实例,但有关用户的所有信息都保留在基类中。
class UserFactory {
public function getUser($type) {
switch($type) {
case User::ORDINARY:
return new OrdinaryUser();
case User::MODERATOR:
return new Moderator();
case User::ADMINISTRATOR:
return new Administrator();
}
}
}
$user = User::getByPK(1); // Has all the information
$factory = new UserFactory();
$object = $factory->getUser($user->type); // Is instance of Administrator
在这种情况下,使用工厂模式的正确方法是什么?
工厂模式的思想是从对象本身分离和封装创建对象实例所需的逻辑。 这将关注点分开。
当前,您的User
类上有一个静态方法,该方法负责从数据库中获取用户信息。 这会将您的User
对象耦合到您的数据库。 它也很僵化。
工厂模式使您可以将这些问题抽象化,并根据需要提供工厂的替代实现(假设每个实现都有一个通用的接口)。 也许创建用户的方式会发生变化,但是您也不想在创建用户所需的任何地方也进行更改-而是如何创建用户。 将此代码隔离到工厂中即可。
如果您已经抽象了DAL,则工厂也可以将其作为DAL的实例。 (我将使用IDataAccessLayer
作为首选DAL的占位符)
class UserFactory {
private IDataAccessLayer $dataAccessLayer;
public function __constructor($dataAccessLayer) {
$this->dataAccessLayer = $dataAccessLayer;
}
public function createUser($userId) {
$userDataSet = $this->dataAccessLayer->someQuery($userId);
switch ($userDataSet->type) {
case UserType::Administrator:
return createAdministrator($userDataSet);
case UserType::Moderator:
return createModerator($userDataSet);
case UserType::Ordinary:
return createOrdinaryUser($userDataSet);
}
}
private function createAdministrator($userDataSet) { /* Create and return an administrator */ }
private function createModerator($userDataSet) { /* Create and return a moderator */ }
private function createOrdinaryUser($userDataSet) { /* Create and return an ordinary user */ }
}
然后,您可以这样使用:
$factory = new UserFactory($dataAccessLayer);
$factory->createUser(1);
(和我在一起,我已经有几年没有编码PHP了,所以我的某些语法可能已经关闭,但是想法是一样的)
现在,就个人而言,您似乎需要在这里进行更详细的介绍。 我将按照存储库模式创建一个UserRepository。 我认为这是因为工厂实际上不应该访问数据库。 它应该只使用数据库中的数据来创建用户。 存储库模式应该负责从数据库中获取数据,然后将数据馈送到工厂模式以获取对象。
class UserRepository {
private IDataAccessLayer $dataAccessLayer;
public function __constructor($dataAccessLayer) {
$this->dataAccessLayer = $dataAccessLayer;
}
public function getUserById($id) {
$userData = $this->dataAccessLayer->fetch(someQuery);
$factory = new UserFactory();
return $factory->createUser($userData);
}
}
然后,您将拥有一个更简单的工厂:
class UserFactory {
public function createUser($userData) {
switch ($userData->type) {
case UserType::Administrator:
return createAdministrator($userData);
case UserType::Moderator:
return createModerator($userData);
case UserType::Ordinary:
return createOrdinaryUser($userData);
}
}
private function createAdministrator($userDataSet) { /* Create and return an administrator */ }
private function createModerator($userDataSet) { /* Create and return a moderator */ }
private function createOrdinaryUser($userDataSet) { /* Create and return an ordinary user */ }
}
从您的代码中,您将得到类似:
$userRepository = new UserRepository($dataAccessLayer); //This is probably done somewhere higher in your code.
$userRepository->getUserById(1);
您可能需要继续创建以下接口并也实现它们。 这将使您能够执行合同,并设置自己以能够根据需要交换实现。
public interface IUserRepository {
function getUserById($userId);
}
和
public interface IUserFactory {
function createUser($userData);
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.