Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/oop/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Php 如何实施工厂设计模式_Php_Oop_Design Patterns - Fatal编程技术网

Php 如何实施工厂设计模式

Php 如何实施工厂设计模式,php,oop,design-patterns,Php,Oop,Design Patterns,我试图将工厂设计模式应用于应用程序中的实际问题。我使用的是数据对象(有点像ORM,但不完全是),其中一个对象表示数据库中的一行,其属性是列。话虽如此,我有3种不同类型的用户,它们都扩展了基类User,并且都保存在users的同一数据库表中。我有一个额外的列type,用于确定用户的类型 因此,要获取id为1的用户,我将使用以下代码: $user = User::getByPK(1); 然而,不同类型的用户具有不同的属性和方法,我需要获得适当的实例,这正是我遇到的问题。我创建了一个工厂类,但我不太

我试图将工厂设计模式应用于应用程序中的实际问题。我使用的是数据对象(有点像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
类上有一个静态方法,负责从数据库中获取用户信息。这将
用户
对象耦合到数据库。它也很硬

  • 如果您的用户存储在不同类型的数据库中怎么办
  • 如果您的用户存储在一个XML文件中呢
  • 如果您的用户存储在密钥/值存储中,该怎么办
  • 如果您想创建一个用户的模拟存储库来编写测试,该怎么办
工厂模式允许您抽象这些关注点,并根据您的需要提供工厂的替代实现(假设每个实现都有一个公共接口)。也许您创建用户的方式会改变,但您不希望在创建用户所需的任何地方也进行更改—只是更改用户的创建方式。将此代码隔离到工厂允许这样做

如果您已经抽象了DAL,工厂也可能会向您的DAL提供一个实例。(我将使用
IDataAccessLayer
作为首选DAL的占位符)

然后,您可以这样使用:

$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);
}


getUser()
Repository
类的方法的好名字。
工厂
类的方法名称通常以
创建
开头,以更好地表达
工厂
的功能:它创建新对象。如果有任何问题令人困惑、没有意义或没有答案,请告诉我,我会修改!不,这太棒了!我只是想知道一件事——因为大多数时候只有一种类型的对象——例如
Note
。我有一个允许用户向自己发布注释的部分,我决定不会有其他类型的注释,只有
Note
。在这种情况下,我认为不需要工厂,我可以将数据从网关直接提供给存储库中的对象构造函数,并让它自己填充。你同意吗?对不起,但我不明白-笔记类如何依赖于图书馆?另外,在进行了一次简短的测试并了解了这个“机制”之后,为了获得一个数据对象,我需要在我的控制器中实例化3个类——存储库、网关和工厂,我需要向它们传递一个db连接,而不是我过去所做的
Model::byPK
。这真的是专业人士编程的方式吗?似乎太复杂了。q_q
注意
依赖于提供包含数据库记录集的域模型的库。在PHP中,这可能没什么大不了的。然而,在一般编程中,这是您应该努力避免的<代码>注意是独立的,因为您说您要在对象上放置一个creator函数/构造函数,该对象需要一个类的实例,该实例只有在加载特定库时才可用。至于你对使用复杂模型的专业程序员的抨击,只有你才能决定你的项目是否需要使用设计模式。这个问题是专门关于设计模式的,所以我不知道你为什么现在放弃使用它们。如果您认为您的项目不够复杂,不需要设计模式,那么就不要使用它们。不过我会告诉你的。实现设计模式和可靠的原则可以使代码维护变得简单得多。在你开始使用它们之前,你根本无法理解它们所解决的问题。
public interface IUserRepository {
    function getUserById($userId);
}
public interface IUserFactory {
    function createUser($userData);
}