面向对象的设计强调“抽象类高于实践”,尽量的将代码设计的通常化,而非特殊化——也就是下降耦合,提高标准性。因而,前辈们便设计了“特定类处理实例化”的工厂方法。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
面对上述难题,咱们有了下列三条要求:面向对象设计模式
在代码运行时,才能了解咱们要生成的对象类型(实时传参,注意那句:$comms = new CommsManager( CommsManager::MEGA )
);对象
相对轻松的加入新数据格式(Product);get
每一个产品类型都能轻松加入订制化功能。
既然如此,咱们干脆将 数据格式们 从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
功能呢?
答案很明显,咱们须要:能够同时处理一组相关实现的架构,解决之道就在下一篇文章:抽象工厂模式。