如何实现工厂设计模式

埃米利奥·罗德里格斯(Emilio Rodrigues)

我正在尝试将工厂设计模式应用于应用程序中的实际问题。我正在使用数据对象(有点像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文件中怎么办?
  • 如果您的用户存储在键/值存储中怎么办?
  • 如果要创建用于编写测试的用户模拟存储库,该怎么办?

工厂模式允许您消除这些顾虑,并根据需要提供工厂的替代实现(假设每个实现都具有一个公共接口)。也许您创建用户的方式会发生变化,但是您不想在创建用户所需的任何地方也进​​行更改-而是如何创建用户。将此代码隔离到工厂中就可以做到这一点。

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

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

工厂设计模式的实现

来自分类Dev

抽象工厂设计模式实现

来自分类Dev

如何在C#中实现工厂设计模式以绘制形状?

来自分类Dev

这是实现工厂方法设计模式的正确方法吗

来自分类Dev

如何实现单一工厂模式?

来自分类Dev

如何实现对象的工厂模式生成?

来自分类Dev

工厂设计模式的困境

来自分类Dev

工厂设计模式

来自分类Dev

比工厂更好的设计模式?

来自分类Dev

工厂模式设计-澄清

来自分类Dev

工厂设计模式优化

来自分类Dev

工厂模式实现的变化

来自分类Dev

如何使用设计模式实现多级继承

来自分类Dev

如何使用设计模式实现多级继承

来自分类Dev

实施工厂设计模式时如何避免“ instanceof”?

来自分类Dev

工厂-那是哪种设计模式?

来自分类Dev

工厂设计模式实施的疑问

来自分类Dev

工厂设计模式和弹簧

来自分类Dev

了解php工厂设计模式

来自分类Dev

设计模式-抽象工厂-BombedMazeFactory

来自分类Dev

使用猫鼬时如何实现工厂模式?

来自分类Dev

如何实现策略模式的创建/工厂关注点?

来自分类Dev

如何在Java中使用泛型实现工厂模式?

来自分类Dev

我的代码是否实现了工厂模式?这是一个糟糕的设计吗?

来自分类Dev

如何在C#中实现单例设计模式?

来自分类Dev

PHP设计模式工厂,存储库和...?

来自分类Dev

工厂设计模式-为什么需要接口?

来自分类Dev

实施工厂设计模式缺失环节

来自分类Dev

抽象工厂和立面,合作设计模式