【面向对象的PHP】之模式:工厂方法

工厂方法模式

面向对象的设计强调“抽象类高于实践”,尽量的将代码设计的通常化,而非特殊化——也就是下降耦合,提高标准性。因而,前辈们便设计了“特定类处理实例化”的工厂方法。segmentfault

问题

Appointment类须要解析BloggsCal数据格式,在类内部,咱们将数据格式写死为BloggsCal,这将会形成耦合,并且实际上,将来业务需求要面临更多的数据格式。设计模式

实现

这个时候咱们引入工厂方法模式,设置CommsManager类(创造者,creater)、ApptEncoder类(产品,Product)。架构

接下来,用户只须要调用CommsManager对象的getApptEncoder方法,就能够获得他们须要的对象,而无需关注这个对象究竟是哪一种数据格式。app

abstract class ApptEncoder {
    abstract function encode();
}

class BloggsApptEncoder extends ApptEncoder {
    function encode()
    {
        return "数据格式为BloggsCal。";
    }
}

class MegaApptEncoder extends ApptEncoder {
    function encode()
    {
        return "数据格式为MegaCal。";
    }
}

class CommsManager {
    const BLOGGS = 1;
    const MEGA = 2;
    private $mode = 1;

    function __construct( $mode ) {
        $this->mode = $mode;
    }

    function getApptEncoder() {
        switch ( $this->mode ) {
            case ( self::MEGA ) :
                return new MegaApptEncoder();
            default:
                return new BloggsApptEncoder();
        }
    }

    function getHeaderText() {
        switch ( $this->mode ) {
            case ( self::MEGA ):
                return "Mega格式的表头";
            default:
                return "BloggsCal格式的表头";
        }
    }

    function getFootText() {
        switch ( $this->mode ) {
            case ( self::MEGA ):
                return "Mega格式的脚页";
            default:
                return "BloggsCal格式的脚页";
        }
    }
}

$comms = new CommsManager( CommsManager::MEGA );
$apptEncoder = $comms->getApptEncoder();
echo $apptEncoder->encode();

注意到CommsManager类的三个getXXX方法了吗?this

一旦数据格式增多、功能增长、数据格式间存在业务差别,就会形成一个新问题:大量的判断语句——包括我本身在内的一些人认为,这是代码腐烂的象征。设计

至少,当重复的代码开始蔓延,咱们不该该感到乐观。(尽管下面的处理方法,在必定程度上也重复了这个错误code

面对上述难题,咱们有了下列三条要求:面向对象设计模式

  1. 在代码运行时,才能了解咱们要生成的对象类型(实时传参,注意那句:$comms = new CommsManager( CommsManager::MEGA ));对象

  2. 相对轻松的加入新数据格式(Product);get

  3. 每一个产品类型都能轻松加入订制化功能。

既然如此,咱们干脆将 数据格式们 从CommsManager中剥离出来,造成单独的子类。

// 产品抽象类、子类的代码,同上。

abstract class CommsManager {
    abstract function getApptEncoder();
    abstract function getHeaderText();
    abstract function getFooterText();
}

class BloggsCommsManager extends CommsManager {
    function getApptEncoder() {
        return new BloggsApptEncoder();
    }

    function getHeaderText() {
        return "BloggsCal格式的表头";
    }

    function getFooterText() {
        return "BloggsCal格式的脚页";
    }
}

class MegaCommsManager extends CommsManager {
    function getApptEncoder() {
        return new MegaApptEncoder();
    }

    function getHeaderText() {
        return "MegaCal格式的表头";
    }

    function getFooterText() {
        return "MegaCal格式的脚页";
    }
}

$comms = new BloggsCommsManager();
$apptEncoder = $comms->getApptEncoder();
echo $apptEncoder->encode();

结果

这样知足了上述的三个要求,可我想,聪明的你已经注意到了:必定程度上,建立者/产品们 产生了代码重复。并且,问题被转移到了工厂方法中,咱们目前只是处理了Appointment功能,若是咱们加入TodoList功能呢?

答案很明显,咱们须要:能够同时处理一组相关实现的架构,解决之道就在下一篇文章:抽象工厂模式。

面向对象设计模式 - 目录

相关文章
相关标签/搜索