gpt4 book ai didi

php - 如何实现工厂设计模式

转载 作者:行者123 更新时间:2023-12-02 04:18:25 25 4
gpt4 key购买 nike

我正在尝试将工厂设计模式应用于应用程序中的现实问题。我正在使用数据对象(有点像 ORM,但不完全一样),其中对象代表数据库中的一行,其属性是列。话虽如此,我有 3 种不同类型的用户,它们都扩展了基类 User,并且都保存在 users 的同一个数据库表中。我有一个额外的列 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 对象耦合到数据库。它也非常严格。

  • 如果您的用户存储在不同类型的数据库中怎么办?
  • 如果您的用户存储在 XML 文件中怎么办?
  • 如果您的用户存储在键/值存储中怎么办?
  • 如果您想创建一个模拟用户存储库来编写测试怎么办?

工厂模式允许您将这些问题抽象出来,并根据您的需要提供工厂的替代实现(假设每个实现都有一个公共(public)接口(interface))。也许您创建用户的方式发生了变化,但您不想同时更改创建用户所需的所有地方 - 只是创建用户的方式。将此代码隔离到工厂中可以实现此目的。

如果您已经抽象了 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);

您可能想要继续创建以下接口(interface)并实现这些接口(interface)。这将使您能够执行契约(Contract),并让自己能够在需要时更换实现。

public interface IUserRepository {
function getUserById($userId);
}

public interface IUserFactory {
function createUser($userData);
}

关于php - 如何实现工厂设计模式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32149376/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com