如何实现工厂设计模式
How to implement factory design pattern
我正在尝试将工厂设计模式应用于应用程序中的实际问题。我正在使用数据对象(有点像 ORM,但不完全是),其中一个对象表示数据库中的一行,其属性是列。话虽如此 - 我有 3 种不同类型的用户,它们都扩展了基础 class User
,并且都保存在 users
的同一个数据库 table 中。我有一个额外的列 type
用于确定用户类型。
所以要获取 ID 为 1 的用户,我将使用此代码:
$user = User::getByPK(1);
但是不同类型的用户有不同的属性和方法,我需要得到合适的实例,这就是我卡住的地方。我创建了一个工厂 class 但我不太确定如何调用它。在确定用户的类型之前,我需要从数据库中获取有关用户的信息,但是我需要实例化适当的 class 并且这两件事相互依赖。
这是我所做的 - 我得到了适当的实例,但用户的所有信息都保存在基础 class。
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
class 上有一个静态方法负责从数据库中获取用户信息。这会将您的 User
对象耦合到您的数据库。也很死板。
- 如果您的用户存储在不同类型的数据库中怎么办?
- 如果您的用户存储在 XML 文件中怎么办?
- 如果您的用户存储在 key/value 商店中怎么办?
- 如果您想创建一个模拟用户存储库来编写测试怎么办?
工厂模式允许您将这些问题抽象化,并根据您的需要提供工厂的替代实现(假设每个实现都有一个通用接口)。也许您创建用户的方式发生了变化,但您不希望在创建用户所需的所有地方都发生变化——只是用户的创建方式。将此代码隔离到工厂中允许这样做。
如果您已经抽象了 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,所以我的一些语法可能不对,但想法是一样的)
现在,就个人而言,您似乎需要在此处更加细化。我将按照 Repository 模式创建一个 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);
}
我正在尝试将工厂设计模式应用于应用程序中的实际问题。我正在使用数据对象(有点像 ORM,但不完全是),其中一个对象表示数据库中的一行,其属性是列。话虽如此 - 我有 3 种不同类型的用户,它们都扩展了基础 class User
,并且都保存在 users
的同一个数据库 table 中。我有一个额外的列 type
用于确定用户类型。
所以要获取 ID 为 1 的用户,我将使用此代码:
$user = User::getByPK(1);
但是不同类型的用户有不同的属性和方法,我需要得到合适的实例,这就是我卡住的地方。我创建了一个工厂 class 但我不太确定如何调用它。在确定用户的类型之前,我需要从数据库中获取有关用户的信息,但是我需要实例化适当的 class 并且这两件事相互依赖。
这是我所做的 - 我得到了适当的实例,但用户的所有信息都保存在基础 class。
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
class 上有一个静态方法负责从数据库中获取用户信息。这会将您的 User
对象耦合到您的数据库。也很死板。
- 如果您的用户存储在不同类型的数据库中怎么办?
- 如果您的用户存储在 XML 文件中怎么办?
- 如果您的用户存储在 key/value 商店中怎么办?
- 如果您想创建一个模拟用户存储库来编写测试怎么办?
工厂模式允许您将这些问题抽象化,并根据您的需要提供工厂的替代实现(假设每个实现都有一个通用接口)。也许您创建用户的方式发生了变化,但您不希望在创建用户所需的所有地方都发生变化——只是用户的创建方式。将此代码隔离到工厂中允许这样做。
如果您已经抽象了 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,所以我的一些语法可能不对,但想法是一样的)
现在,就个人而言,您似乎需要在此处更加细化。我将按照 Repository 模式创建一个 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);
}