问题
假设有一个关于个人事务管理的项目,其功能之一是管理Appointment(预约)对象。我们的业务团队和另一个公司建立了联系,目前需要用一个叫做BloggsCal的格式来和他们交流预约相关的数据。但是将来也可能面对更多的格式。
在接口级别上,我们可以立即定义两个类。其一是需要一个数据编码器来把Appointment对象转换成一个专有的格式,将这个编码器命名为ApptEncoder类;另外需要一个管理员来获得编码器,并使用编码器与第三方通信,我们将这个管理类命名为CommsManager类。(CommsManager:创建者;ApptEncoder:产品)
<?php
abstract class ApptEncoder
{
abstract function encode();
}
class MegaApptEncoder extends ApptEncoder
{
function encode()
{
return "Appointment data encoded in MegaCal format\n";
}
}
class BloggsApptEncoder extends ApptEncoder
{
function encode()
{
return "Appointment data encoded in BloggsCal format\n";
}
}
class CommsManager
{
const BLOGGS = 1;
const MEGA = 2;
private $mode;
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 "MegaCal header\n";
default :
return "BloggsCal header\n";
}
}
}
$comms = new CommsManager(CommsManager::MEGA);
$apptEncoder = $comms->getApptEncoder();
print $apptEncoder->encode();
问题
正如你看到的,支持页眉输出的需求迫使我们重复条件判断语句。如果我们加入新协议,这种做法就不适用了。如果要加入getFooterText()方法,工作量就会更大。
解决
把CommsManager重新指定为抽象类。这样我们可以得到一个灵活的父类,并把所有特定协议相关的代码放到具体的子类中。
<?php
abstract class ApptEncoder
{
abstract function encode();
}
class BloggsApptEncoder extends ApptEncoder
{
function encode()
{
return "Appointment data encode in BlogCal format\n";
}
}
abstract class CommsManager
{
abstract function getHeaderText();
abstract function getApptEncoder();
abstract function getFooterText();
}
class BloggsCommsManager extends CommsManager
{
function getHeaderText()
{
return "BloggsCal header\n";
}
function getApptEncoder()
{
return new BloggsApptEncoder();
}
function getFooterText()
{
return "BloggsCal Footer\n";
}
}