与简单工厂相比,使用工厂方法模式有什么优势?

时间:2018-11-19 10:35:40

标签: php design-patterns factory-pattern factory-method

我正在阅读有关工厂方法模式和简单工厂的信息。事实证明,简单的工厂就足够了,我看不到工厂方法模式的用例。请阅读此链接https://www.binpress.com/factory-design-pattern/,我会提问。

1)在简单工厂中,它说这很不好,因为它违反了打开/关闭原则。我知道,但是在工厂方法模式下,它仍然违反了打开/关闭的原则。

if ('car'==$toyName) {
            $toy = new NyCar();
        } else if ('helicopter'==$toyName) {
            $toy = new NyHelicopter();
        }

如果纽约要有一个新的面包店,我们需要在这里添加。

2)在阅读链接之后,在实际上达到更好的解决方案之前,它使用了以下代码。 :

class NySimpleFactory {
    public function createToy($toyName) {
        $toy = null;

        if ('car'==$toyName) {
            $toy = new NyCar();
        } else if ('helicopter'==$toyName) {
            $toy = new NyHelicopter();
        }

        return $toy;
    }
}

class NyToysFactory {

    public $simpleFactory;

    public function __construct(SimpleFactory $simpleFactory) {
        $this->simpleFactory = $simpleFactory;
    }

    public function produceToy($toyName) {
        $toy = null;
        $toy = $this->simpleFactory->createToy($toyName);
        $toy->prepare();
        $toy->package();
        $toy->label();
        return $toy;
    }
}

然后说,

  

开发人员快速完成新代码并将其移交给美国   工厂。两周后,手机开始响铃   开发人员办公室,因为纽约工厂正在生产   问题。原来NyToysFactory类已被修改   远程分支的开发人员,因为员工不想做   包装和标签工作。他们通过删除来修改了ProduceToy()   其label()和package()函数。

     

在这种情况下,简单工厂似乎无法正常工作。我们不   希望美国的分支机构能够修改ProduceToy()函数。   ProduceToy()应包含一组标准过程,并且   分支机构仅应负责创建特定于位置的信息   玩具。如果他们可以创建一个抽象类怎么办?和抽象   他们创建的类将具有具体的ProduceToy()方法   实施所有分支机构的一套标准操作程序   必须遵循。在ProduceToy()内部,它调用自己的抽象方法   createToy()获取玩具类。这样createToy()能够   封装对象创建,并且由于它是抽象的,因此将对象   创建到其子类。

问题是:a)将其移交给美国工厂意味着什么? b)或我们不希望美国的分支机构能够修改ProduceToy()函数。他们仍然可以修改ProduceToy函数,如果他们不能或者可以改变它,那有什么不同?我只是不明白为什么简单工厂对下面的示例根本不好。

无需在该链接上了解抽象工厂

1 个答案:

答案 0 :(得分:2)

T 他的代码/问题 不会阐明“抽象工厂”或“工厂方法”。通过打开参数来确定要实例化哪个类的确是一种反模式,它鼓励违反开放式/封闭式原则。

抽象工厂

抽象工厂是关于强制相关类的家族的全部内容:

abstract class ToyFactory
+ createBear(): ToyBear
+ createElephant(): ToyElephant

class USToyFactory extends ToyFactory
+ createBear(): ToyBear -> creates USToyBear
+ createElephant(): ToyElephant -> USToyElephant

abstract class ToyBear
+ playSound()

class USToyBear extends ToyBear
+ playSound()//play US National Anthem

通过一个预期有ToyFactory的USToyFactory会强制创建美国玩具(USToyBear和USToyElephant)–这就是Abstract Factory的力量。

注意,产品(熊,大象等)是已知的AoT(提前出现)。

工厂方法

Factory方法只与将实例化延迟到子类有关。

abstract class Dashboard
+ createWidget(): Widget

abstract class Widget
+ config()

class StatsDashboard extends Dashboard
+ createWidget: Widget -> return new StatsWidget()

class StatsWidget extends Widget

调用createWidget()返回一个Widget,但是必须将要返回的具体Widget推迟到子类中(StatsDashboard返回StatsWidget)。

请注意,创建方法在继承树上声明,但在继承树下实现。

❧敏锐的读者会看到Abstract Factory方法类似于Factory Methods,这是巧合吗? –不。这是工厂方法名称的来源(它们执行具体的类实例化)。

关于“美国工厂”的困惑是正确的;这是糟糕的单词选择。作者暗示此代码可能会传递给工厂工人,这与工厂模式完全无关且令人困惑。


要解决上面的切换,您需要认识到显而易见的情况:每个条件处理程序都以某种方式关联。在这种情况下,它们都是玩具。

public function createToy($toyName) {
    $toy = null;

    if ('car'==$toyName) {
        $toy = new NyCar();//I'm a Toy
    } else if ('helicopter'==$toyName) {
        $toy = new NyHelicopter();//I'm a Toy
    }

    return $toy;
}

使用多态性,我们可以通过创建一组同级类来满足开闭原则:

abstract class Toy
+ operate()

Car extends Toy
Helicopter extends Toy

some_toy.operate();

添加到切换案例只不过是创建另一个同级类。

Dependency injection应该用于实例化具体的Toy。

我希望这会有所帮助!