1

我正在学习 php 中的工厂设计模式。据我了解,这种模式在我们有一堆类的情况下很有用,比如class_1、class_2、class_3等。如果必须实例化的特定类仅在运行时才知道,那么不要使用新的运算符为这些类创建对象,我们创建一个工厂类来为我们完成这项工作。

工厂类看起来有点像这样:

class Factory
{
// $type will have values 1, 2, 3 etc.
public function create_obj($type)
{
  $class_name = "class_".$type;
  if(class_exists($class_name))
  {
        return new $class_name();
  } 
}
}

我的问题是在这里使用工厂有什么好处?为什么不只使用一个简单的函数而不是一个会使事情复杂化的类呢?

4

4 回答 4

2

您的代码片段中的方法不是工厂方法,而只是一个辅助方法,它执行一项众所周知的反射任务:根据其名称实例化一个类。这与工厂模式的用途完全相反:创建对象(产品)而不指定将要创建的对象的确切类

正如维基百科中所解释的:

这种模式的本质是“定义一个用于创建对象的接口,但让实现该接口的类决定实例化哪个类”。

您可能对Wikipedia 关于工厂模式的文章中的最后一个PHP 示例感到困惑,是的,这是一个糟糕的示例。检查上面的Java 示例以获得有意义的示例(尝试将其转换为 PHP 的人错过了整个要点)。Java 示例根据其扩展名返回一个文件读取器,这正是工厂模式的用例。创建您自己的个人“规则”,即某些类需要具有某个名称前缀,这很可能是一个糟糕的设计决策。

于 2013-01-30T16:44:07.927 回答
1

在问题的基本根源上,您可以使用一个简单的函数来实现目标。这打破了程序员的最佳实践,你想要低耦合,高内聚。

函数本身在您的应用程序设计中扮演着特殊的角色,并且将其与具有不同角色和目的的其他函数放在一起是不直观的维护和阅读。请记住,模式用于简化项目域(几乎)普遍面临的常见问题,因此它们倾向于与代码库的其余部分分离,以帮助区分它们。

此外,通过将模式放在它自己的类中,任何需要使用它的类都不需要知道 class_1/2/3/etc 的类结构。而是只需要引用父类,允许您创建更多的类,相应地修改模式,而无需解决剩余代码中的依赖关系和链接。这与低耦合有关。

于 2013-01-30T14:56:15.937 回答
1

使用工厂模式的另一个重要原因是考虑当您必须在设计和代码中添加类时代码会发生什么。
如果您不使用工厂模式,您的代码将越来越紧密地耦合,您将不得不在许多不同的地方进行更改。您必须确保您必须接触代码的每个地方都与您必须接触的所有其他(紧密耦合的)地方相协调。 测试变得非常复杂,而且有些东西会坏掉。

工厂模式为您提供了一种减少耦合的方法,并帮助您将职责封装到几个地方。使用工厂模式,添加额外的类意味着在更少的地方接触代码。简化了测试(构建测试用例以及运行测试)。

在现实世界中,大多数代码“足够”复杂,工厂模式的好处显而易见。更改、改进和扩展对象模型,在快速变化的情况下尽可能完整和严格地进行测试,并确保您的代码尽可能不死板(同时要意识到多个人将在几个月/几年的时间里一直在努力)——工厂模式通常是不费吹灰之力的。

举一个简单的例子,很难看出使用工厂模式的优势。(如果你的代码真的很琐碎,那么这种模式可能不会给你带来太多收益。)这是我在网上搜索时看到的许多示例的问题——这些示例往往侧重于“你可以确定在运行时上课!并且很简单。

这是一个不太简单的例子,我认为让人们思考该模式的所有可能好处: Bob Tarr 的工厂模式演示文稿 (pdf)。(示例 2,从第 10 页开始。)假设您正在编写一个迷宫游戏,其中一个人必须探索迷宫和迷宫中的所有房间。您的对象模型包括一个由DoorsRoomsWalls之类的东西组成的Maze,并且还有一个Map也必须跟踪它们。很简单。但是当你开始添加魔法房间和魔法门和魔法窗户时会发生什么?会说话的图片曲折的小段落?你最终会得到很多类来代表一切;您要确保在添加新类时必须更改(触摸)尽可能少的代码。并且您不希望修改Map类中的代码,例如,每次添加新类时:您希望使这些类专注于它们真正应该负责的内容。

不仅要考虑在运行时实例化的内容,还要考虑代码的复杂性。
他还举了一个在 UI 组件中使用工厂模式(特别是工厂方法)的示例——工厂模式在其中出现了很多。(对于初学者,或者从未处理过 UI 代码的人,我认为这个例子不是很清楚。)

请记住,大多数编码都是在现有代码上完成的:大部分时间都花在修改已经存在的代码上。您希望确保您的代码能够在不脆弱的情况下处理更改。减少耦合和封装责任将大大有助于实现这一目标。

于 2013-02-18T08:40:35.380 回答
1

这个概念是你设计一个接口,然后你可以在以后换掉这个类。

暂时忘记这种模式,考虑一下:

if (type == "manager")
    employee = new manager();
else
    employee = new employee();

employee.name = "myname";

在这种情况下,员工和经理都继承自同一个类。在 if 语句之后,您可以像对待人一样对待它们,并且从它们的实际实现中抽象出来。您可以实现工厂模式,而不是到处都有 if 语句。如果你只有一对,那么这种模式可能是矫枉过正的。如果您想在将来轻松扩展程序,请考虑一种模式。

于 2013-01-30T14:58:15.060 回答