中国自古有重男轻女的观念,在古代,未婚女子要想出去逛街都要经过父亲的同意,而有丈夫的则要请示丈夫,如果丈夫去世了,有儿子的还得请示儿子,这就是所谓的“三从”。果然很苦逼!我们用程序来模拟一下这个过程:
<?php
interface IWomen{
public function gettype();
public function getRequest();
}
class Women implements IWomen{
/*
* 1--未出嫁
* 2--出嫁
* 3--夫死
*/
private $type = 0;
private $request = '';
public function __construct( $type, $request ) {
$this->type = $type;
$this->request = $request;
}
public function gettype() {
return $this->type;
}
public function getRequest() {
return $this->request;
}
}
interface IHandler{
public function handleMessage( $women );
}
class Father implements IHandler{
public function handleMessage( $women ) {
echo "女儿的请求是".$women->getRequest()."\n";
echo "父亲的答复是:同意!\n";
}
}
class Husband implements IHandler{
public function handleMessage( $women ) {
echo "妻子的请求是".$women->getRequest()."\n";
echo "丈夫的答复是:同意!\n";
}
}
class Son implements IHandler{
public function handleMessage( $women ) {
echo "母亲的请求是".$women->getRequest()."\n";
echo "儿子的答复是:同意!\n";
}
}
for($type = 1;$type<=3;$type++):
$women = new Women($type,'逛街');
switch ($type) {
case '1':
$handler = new Father();
break;
case '2':
$handler = new Husband();
break;
default:
$handler = new Son();
break;
}
$handler->handleMessage($women);
endfor;
?>
运行结果:
女儿的请求是逛街
父亲的答复是:同意!
妻子的请求是逛街
丈夫的答复是:同意!
母亲的请求是逛街
儿子的答复是:同意!
[Finished in 0.1s]
实现很简单,代码也比较容易,但是这样的设计有几个问题:
1、职责界定不清晰
对女儿的提出的请示,应该在父亲类中做出决定,父亲有责任、有义务处理女儿的请求。因此Father类应该是知道女儿的请求自己处理,而不是在Client中进行组装出来,也就是说原本应该是父亲这个类做的事情抛给了其他地方进行处理。
2、代码臃肿
在client中写了swith判断条件,而且能随着能处理该类型的请示人员越多,switch判断就越多,这样倒置可读性大大下降。
3、耦合过重
client根据women的type来决定使用IHandler的哪个实现类来处理请求。但如果IHandler的实现类继续扩展呢,那就得修改client,与开闭原则违背了!
4、异常情况欠考虑
如果妻子是个不懂三从的人,她已有丈夫却向父亲去请示,那父亲应该如何处理?上面的程序完全没有考虑这种异常情况!
那该如何改进?不难发现,整个请示的过程可以构成一条“链”。“链头“是父亲,无论女子是否已结婚全都请示父亲,父亲得知女儿结婚了,就传给女儿的丈夫,丈夫如果过世了,再传给儿子。看下类图:
实现代码如下:
<?php
interface IWomen{
public function gettype();
public function getRequest();
}
class Women implements IWomen{
/*
* 1--未出嫁
* 2--出嫁
* 3--夫死
*/
private $type = 0;
private $request = '';
public function __construct( $type, $request ) {
$this->type = $type;
$this->request = $request;
}
public function gettype() {
return $this->type;
}
public function getRequest() {
return $this->request;
}
}
abstract class IHandler {
const FATHER_LEVEL_REQUEST = 1;
const HUSBAND_LEVEL_REQUEST = 2;
const SON_LEVEL_REQUEST = 3;
private $level = 0;
private $nextHandler;
protected function __construct( $level ) {
$this->level = $level;
}
final public function handleMessage( $women ) {
if ( $women->getType() == $this->level )
$this->reponse( $women );//这里回调子类方法
else {
if ( $this->nextHandler != NULL )
$this->nextHandler->handleMessage( $women );
else
echo "没地方请示了,按不同意处理!\n";
}
}
public function setNext( $handler ) {
$this->nextHandler = $handler;
}
abstract protected function reponse( $women );
}
class Father extends IHandler{
public function __construct() {
parent::__construct( parent::FATHER_LEVEL_REQUEST );
}
public function reponse( $women ) {
echo "女儿的请求是".$women->getRequest()."\n";
echo "父亲的答复是:同意!\n";
}
}
class Husband extends IHandler{
public function __construct() {
parent::__construct( parent::HUSBAND_LEVEL_REQUEST );
}
public function reponse( $women ) {
echo "妻子的请求是".$women->getRequest()."\n";
echo "丈夫的答复是:同意!\n";
}
}
class Son extends IHandler{
public function __construct() {
parent::__construct( parent::SON_LEVEL_REQUEST );
}
public function reponse( $women ) {
echo "母亲的请求是".$women->getRequest()."\n";
echo "儿子的答复是:同意!\n";
}
}
for($i=0;$i<=3;$i++){
$women = new Women($i,'逛街');
$father = new Father();
$husband = new Husband();
$son = new Son();
$father->setNext($husband);
$husband->setNext($son);
$father->handleMessage($women);
}
?>
运行结果:
没地方请示了,按不同意处理!
女儿的请求是逛街
父亲的答复是:同意!
妻子的请求是逛街
丈夫的答复是:同意!
母亲的请求是逛街
儿子的答复是:同意!
[Finished in 0.1s]
例子中不难发现,其实还用到了模板方法模式。
责任链模式的定义
使多个对象都有机会处理请求,从而避免了请求的发送者和接受者之间耦合关系,将这些对象连成一条链,并沿着这条链传递该请求,直到有对象处理它为止。
责任链模式的优点
最为显著的优点就是将请求和处理分开。请求者可以不用知道是谁处理的,处理者可以不用知道请求的全貌,两者解耦,提高系统的灵活性。
责任链模式的缺点
一是性能问题,每个请求都是从链头遍历到链尾,特别是在链比较长的时候,性能是一个问题。二是调试不是很方便,特别是链条比较长的,环节比较多的时候,由于采用了类似递归的方式 ,调试的时候逻辑可能比较复杂。