深入PHP面向对象、模式与实践——生成对象(2)

来源:互联网 发布:韩国制衣软件 编辑:程序博客网 时间:2024/04/30 21:31

工厂方法模式

面向对象设计强调“抽象类高于实现”。也就是说,我们要尽量一般化而不是特殊化。工厂方法模式解决了当代码关注于抽象类型时如何创建对象实例的问题。答案便是用特定的类来处理。

工厂方法模式把创建者类与要生产的产品类分离开来。创建者是一个工厂类,其中定义了用于生成产品对象的类方法。如果没有提供默认实现,那么就由创建者类的子类来执行实例化。一般情况下,就是创建者类的每个子类实例化一个相应产品子类。

这里写图片描述

abstract class ApptEncoder{    abstract function encode();}class BloggsApptEncoder extends ApptEncoder{    function encode()    {        return "Appointment data encode in BloggsCal format\n";    }}abstract class CommsManager{    abstract function getHeaderText();    abstract function getFooterText();    abstract function getApptEncoder();}class BolggsCommsManager extends CommsManager{    function getHeaderText()    {        return "BloggsCal header\n";    }    function getApptEncoder()    {        return new BloggsApptEncoder();    }    function getFooterText()    {        return "BloggsCal footer\n";    }}

现在当我们被要求实现MegaCal时,只需要给CommsManager抽象类写一个新的实现。如图:
这里写图片描述

  • 结果

请注意我们的创建者类与产品的层次结构是非常相似的。这是使用工厂方法模式的常见结果,这形成了一种特殊的代码重复,因而被一些人所不喜欢。另一个问题是这会导致不必要的子类化。如果你为创建者类创建子类的原因只是为了实现工厂方法模式,那么最好再考虑一下。

抽象工厂模式

在大型应用中,我们很可能需要工厂来生产一组相关的类。抽象工厂模式可以解决这个问题。

这里写图片描述

abstract class CommsManager{    abstract function getHeaderText();    abstract function getFooterText();    abstract function getApptEncoder();    abstract function getTtdEncoder();    abstract function getContactEncoder();}class BolggsCommsManager extends CommsManager{    function getHeaderText()    {        return "BloggsCal header\n";    }    function getApptEncoder()    {        return new BloggsApptEncoder();    }    function getFooterText()    {        return "BloggsCal footer\n";    }    function getContactEncoder()    {        return new BloggsContactEncoder();    }    function getTtdEncoder()    {        return new BloggsTtdEncoder();    }}

请注意,这个例子中我们使用了工厂方法模式。设计模式间经常会这样协作:一个模式创建可以把它自己引入到另一个模式的上下文环境。

  • 结果

那么这个模式带来了什么?

  1. 首先,将系统与实现的细节分离开来。
  2. 对系统中功能相关的元素强制进行组合。
  3. 添加新产品将会令人苦恼。

我们可以创建一个使用标志参数来决定返回什么对象的单一的make()方法,而不是给每一个工厂方法创建独立的方法。

abstract class CommsManager{    const APPT = 1;    const TTD = 2;    const CONTACT = 3;    abstract function getHeaderText();    abstract function make($flag_int);    abstract function getFooterText();}class BolggsCommsManager extends CommsManager{    function getHeaderText()    {        return "BloggsCal header\n";    }    function make($flag_int)    {        switch ($flag_int) {            case self::APPT:                return new BloggsApptEncoder();            case self::CONTACT:                return new BloggsContactEncoder();            case self::TTD:                return new BloggsTtdEncoder();        }    }    function getFooterText()    {        return "BloggsCal footer\n";    }}

可以看出,类的接口变得更加紧凑了。但是这样做也有一定代价。使用单一的make()方法,我们必须在所有的具体创建者中支持所有的产品对象。同时,我们引入了平行条件,因为每个具体创建者都必须实现相同的标志检测。客户类无法确定具体的创建者是否可以生成所有产品,因为make()方法的内部需要对每种情况都进行考虑并作出选择。

另一方面,我们可以创建更灵活的创建者。创建者基类可以提供make()方法来保证每个产品家族有一个默认的实现。具体子类可以选择性地改变这一行为。子类可以实现自己的make()方法并调用,由此决定生成何种对象。这些创建者子类可以自行决定是否在执行自己的make()方法后调用父类的make()方法。

1 0
原创粉丝点击