中国古代对妇女制定了“三从四德”的道德规范,“三从”是指“未嫁从父、既嫁从夫、夫死从子”,也就是说一个女性,在没有结婚的时候要听从于父亲,结了婚后听从于丈夫,丈夫死了还要听儿子的,举个例子来说,一个女的要出去逛街,同样这样的一个请求,在她没有出嫁前她必须征得父亲的同意,出嫁之后必须获得丈夫的许可,那丈夫死了怎么办?一般都是男的比女的死的早,还要问问儿子是否允许自己出去逛街,估计你下边马上要问要是没有儿子怎么办?请示小叔子、侄子等等,在父系社会中,妇女只占从属地位,现在想想中国的妇女还是比较悲惨的,逛个街还要请示来请示去,而且作为父亲、丈夫、儿子只有两种选择:要不承担起责任来告诉她允许或不允许逛街,要不就让她请示下一个人,这是整个社会体系的约束,应用到我们项目中就是业务规则,那我们来看怎么把“三从”通过我们的程序来实现,需求很简单:通过程序描述一下古代妇女的“三从”制度,好我们先看类图:

  非常简单的类图,这个实现也非常简单,我们先看 IWomen 接口:

 package com.pattern.chainOfResponsibility;

 /**
* 古代悲哀女性的总称
* @author http://www.cnblogs.com/initial-road/
*
*/
public interface IWomen { // 获得个人状况
public int getType(); //获得个人请示,你要干什么?出去逛街?约会?还是看电影
public String getRequest(); }

  女性就两个参数,一个是当前的个人状况,是结婚了呢还是没结婚,丈夫有没有去世,另外一个是要请示的内容,要出去逛街呀还是吃饭,我们看实现类:

 package com.pattern.chainOfResponsibility;

 /**
* 古代女性的总称
* @author http://www.cnblogs.com/initial-road/
*
*/
public class Women implements IWomen{ // 通过一个int类型的参数来描述妇女的个人状况
private int type = 0; // 妇女的请示
private String request = ""; // 构造函数传递过来请求
public Women(int _type, String _request){
this.type = _type;
this.request = _request;
} // 获得妇女的请求
public String getRequest() {
return this.request;
} // 获得自己的状况
public int getType() {
return this.type;
} }

  我们使用数字来代表女性的不同状态,1 是未结婚,2 是已经结婚的,而且丈夫建在,3 是丈夫去世了的。我们再来看有处理权的人员接口:

 package com.pattern.chainOfResponsibility;

 /**
* 父系关系,那就是男性有至高权利,handler控制权
* @author http://www.cnblogs.com/initial-road/
*
*/
public interface IHandler { // 一个女性(女儿,妻子或者是母亲)要求逛街,你要处理这个请求
public void handleMessage(IWomen women); } // 父亲、丈夫、儿子都是这个 IHandler 接口的实现者: package com.pattern.chainOfResponsibility; /**
* 父亲
* @author http://www.cnblogs.com/initial-road/
*
*/
public class Father implements IHandler { // 未出嫁女儿来请求父亲
public void handleMessage(IWomen women) {
System.out.println("女儿的请求是:" + women.getRequest());
System.out.println("父亲的答复是: 同意");
} } package com.pattern.chainOfResponsibility; /**
* 丈夫类
* @author http://www.cnblogs.com/initial-road/
*
*/
public class Husband implements IHandler { // 妻子向丈夫请示
public void handleMessage(IWomen women) {
System.out.println("妻子的请示是:" + women.getRequest());
System.out.println("丈夫的答复是: 同意");
} } package com.pattern.chainOfResponsibility; /**
* 儿子类
* @author http://www.cnblogs.com/initial-road/
*
*/
public class Son implements IHandler { // 目前向儿子请示
public void handleMessage(IWomen women) {
System.out.println("母亲的请示是:" + women.getRequest());
System.out.println("儿子的答复是: 同意");
} }

  这三个类非常非常的简单,就一个方法,处理女儿、妻子、母亲提出的请求,再来看 Client 是怎么组装的:

 package com.pattern.chainOfResponsibility;

 import java.util.ArrayList;
import java.util.Random; /**
* 我们后人来看这样的社会道德
* @author http://www.cnblogs.com/initial-road/
*
*/
public class Client { public static void main(String[] args) {
// 随机挑选几个女性
Random rand = new Random();
ArrayList<IWomen> arrayList = new ArrayList<IWomen>();
for(int i=0;i<5;i++){
arrayList.add(new Women(rand.nextInt(4), "我要出去逛街"));
} // 定义三个请示对象
IHandler father = new Father();
IHandler husband = new Husband();
IHandler son = new Son(); for(IWomen women : arrayList){
// 未结婚少女,请示父亲
if(women.getType() == 1){
System.out.println("\n-----女儿向父亲请示-----\n");
father.handleMessage(women);
}else if(women.getType() == 2){
System.out.println("\n-----妻子向丈夫请示-----\n");
husband.handleMessage(women);
}else if(women.getType() == 3){
System.out.println("\n-----母亲向儿子请示-----\n");
son.handleMessage(women);
}else {
// 暂时啥也不做
}
} } }

  首先是通过随机方法产生了 5 个古代妇女的对象,她们是如何就逛街这件事去请示的(由于是随机的,您看到得结果可能和这里有所不同)。

  “三从四德”的旧社会规范已经完整的表现出来了,你看谁向谁请示都定义出来了,但是你是不是发现这个程序写的有点不舒服?有点别扭?有点想重构它的感觉?那就对了!这段代码有以下几个问题:

  失去面向对象的意义。对女儿提出的请示,应该在父亲类中做出决定,父亲这个类应该是知道女儿的请求应该自己处理,而不是在 Client 类中进行组装出来,也就是说原本应该是父亲这个类做的事情抛给了其他类进行处理;

  迪米特法则相违背。我们在 Client 类中写了 if…eles 的判断条件,你看这个条件体内都是一个接口IHandler 的三个实现类,谁能处理那个请求,怎么处理,直接在实现类中定义好不就结了吗?你的类我知道的越少越好,别让我猜测你类中的逻辑,想想看,把这段 if…else 移动到三个实现类中该怎么做?

  耦合过重。这是什么意思呢,我们要根据 Women 的 type 来决定使用 IHandler 的那个实现类来处理请求,我问你,如果 IHanlder 的实现类继续扩展怎么办?修改 Client 类?与开闭原则违背喽!

  异常情况没有考虑。妻子只能向丈夫请示吗?如果妻子向自己的父亲请示了,父亲应该做何处理?我们的程序上可没有体现出来。

  既然有这么多的问题,那我们要想办法来解决这些问题,我们可以抽象成这样一个结构,女性的请求先发送到父亲类,父亲类一看是自己要处理的,就回应处理,如果女儿已经出嫁了,那就要把这个请求转发到女婿来处理,那女婿一旦去天国报道了,那就由儿子来处理这个请求,类似于这样请求:

  父亲、丈夫、儿子每个节点有两个选择:要么承担责任,做出回复;要么把请求转发到后序环节。结构分析的已经很清楚了,那我们看怎么来实现这个功能,先看类图:

  从类图上看,三个实现类 Father、Husband、Son 只要实现构造函数和父类的中抽象方法就可以了,具体怎么处理这些请求,都已经转移到了Hanlder 抽象类中,我们来看 Hanlder 怎么实现:

 package com.pattern.chainOfResponsibility.advance;

 import com.pattern.chainOfResponsibility.IWomen;

 /**
* 父系社会,那就是男性有至高权利,handler控制权
* @author http://www.cnblogs.com/initial-road/
*
*/
public abstract class Handler { // 能处理的级别
private int level = 0; // 责任传递,下一个责任人是谁
private Handler nextHandler; // 每个类都要说明一下自己能处理那些请求
public Handler(int _level){
this.level = _level;
} // 一个女性(女儿,妻子或者是母亲)要求逛街,你要处理这个请求
public final void handleMessage(IWomen women){
if(women.getType() == this.level){
this.response(women);
}else{
if(this.nextHandler != null){ // 有后续环节,才把请求往后传送
this.nextHandler.response(women);
}else{
// 已经没有后续处理人了,不用处理了
System.out.println("-----没地方请示了,不做处理了!-----\n");
}
}
} /**
* 如果你属于你处理的返回,你应该让她找下一个环节的人,比如
* 女儿出嫁了,还向父亲请示是否可以逛街,那父亲就应该告诉女儿,应该找丈夫请示
*/
public void setNext(Handler _handler){
this.nextHandler = _handler;
} // 有请示那当然要回应
public abstract void response(IWomen women);
}

  有没有看到,其实在这里也用到模版方法模式,在模版方法中判断请求的级别和当前能够处理的级别,如果相同则调用基本方法,做出反馈;如果不相等,则传递到下一个环节,由下一环节做出回应。基本方法 response 要各个实现类都要实现,我们来看三个实现类:

 package com.pattern.chainOfResponsibility.advance;

 import com.pattern.chainOfResponsibility.IWomen;

 /**
* 父亲
* @author http://www.cnblogs.com/initial-road/
*
*/
public class Father extends Handler { // 父亲只处理女儿的请求
public Father() {
super(1);
} // 父亲的答复
public void response(IWomen women) {
System.out.println("-----女儿向父亲请示-----");
System.out.println(women.getRequest());
System.out.println("父亲的答复是: 同意\n");
} } package com.pattern.chainOfResponsibility.advance; import com.pattern.chainOfResponsibility.IWomen; /**
* 丈夫类
* @author http://www.cnblogs.com/initial-road/
*
*/
public class Husband extends Handler { // 丈夫只处理妻子的请求
public Husband() {
super(2);
} // 丈夫请示的答复
public void response(IWomen women) {
System.out.println("-----妻子向丈夫请示-----");
System.out.println(women.getRequest());
System.out.println("丈夫的答复是: 同意\n");
} } package com.pattern.chainOfResponsibility.advance; import com.pattern.chainOfResponsibility.IWomen; /**
* 儿子类
* @author http://www.cnblogs.com/initial-road/
*
*/
public class Son extends Handler { // 儿子只处理母亲的请求
public Son() {
super(3);
} // 儿子的答复
public void response(IWomen women) {
System.out.println("-----母亲向儿子请示-----");
System.out.println(women.getRequest());
System.out.println("儿子的答复是: 同意\n");
} }

  这三个类都很简单,构造方法那是你必须实现的,父类已经定义了,子类不实现编译不通过,通过构造方法我们设置了各个类能处理的请求类型,Father 只能处理请求类型为 1(也就是女儿)的请求; Husband只能处理请求类型类 2(也就是妻子)的请求;儿子只能处理请求类型为 3(也就是目前)的请求。

  Women 类的接口没有任何变化,实现类少有变化,看代码:

 package com.pattern.chainOfResponsibility.advance;

 import com.pattern.chainOfResponsibility.IWomen;

 /**
* 古代女性的总称
* @author http://www.cnblogs.com/initial-road/
*
*/
public class Women implements IWomen { // 通过一个int类型的参数来描述妇女的个人状况
private int type = 0; // 妇女的请示
private String request = ""; // 构造函数传递过来请求
public Women(int _type, String _request){
this.type = _type;
switch(this.type){
case 1:
this.request = "女儿的请求是:" + _request;
break;
case 2:
this.request = "妻子的请求是:" + _request;
break;
case 3:
this.request = "母亲的请求是:" + _request;
break;
}
} // 获得妇女的请求
public String getRequest() {
return this.request;
} // 获得自己的状况
public int getType() {
return this.type;
} }

  就是为了展示结果清晰一点,Women 类做了一点改变。我们再来看 Client 类是怎么描述古代这一个礼节的:

 package com.pattern.chainOfResponsibility.advance;

 import java.util.ArrayList;
import java.util.Random;
import com.pattern.chainOfResponsibility.IWomen; /**
* 我们后人来看这样的社会道德
* @author http://www.cnblogs.com/initial-road/
*
*/
public class Client { public static void main(String[] args) {
// 随机挑选几个女性
Random rand = new Random();
ArrayList<IWomen> arrayList = new ArrayList<IWomen>(); for(int i=0;i<5;i++){
arrayList.add(new Women(rand.nextInt(4), "我要出去逛街"));
} // 定义三个请示对象
Handler father = new Father();
Handler husband = new Husband();
Handler son = new Son(); // 设置提示顺序
father.setNext(husband);
husband.setNext(son); for(IWomen women : arrayList){
father.handleMessage(women);
}
} }

  结果也正确,业务调用类 Client 也不用去做判断到底是需要谁去处理,而且 Handler 抽象类的子类以后可以继续增加下去,只是我们这个传递链增加而已,调用类可以不用了解变化过程,甚至是谁在处理这个请求都不用知道。

  以上讲解的就是责任链模式,你看 Father、Husband、Son 这三个类的处理女性的请求时是不是在传递呀,每个环节只有两个选项:要么承担责任做出回应,要么向下传递请求,最终会有环节做出回应,通用类图如下:

  在通用类图中 Handler 是一个接口或者是抽象类,每个实现类都有两个方法 HandlerRequest 是处理请求,setNext 是设置当前环节怎么把不属于自己处理的请求扔给谁,对于这个类图我觉得需要改变,融合进来模版方法模式,类图如下:

  想想单一职责法则和迪米特法则吧,通过融合模版方法模式,各个实现类只要关注的自己业务逻辑就成了,至于说什么事要自己处理,那就让父类去决定好了,也就是说父类实现了请求传递的功能,子类实现请求的处理,符合单一职责法则,各个类只作一个动作或逻辑,也就是只有一个原因引起类的改变,我 建议大家在使用的时候用这种方法,好处是非常明显的了,子类的实现非常简单,责任链的建立也非常的灵活。

24种设计模式--责任链模式【Chain ofResponsibility Pattern】的更多相关文章

  1. 23种设计模式--责任链模式-Chain of Responsibility Pattern

    一.责任链模式的介绍 责任链模式用简单点的话来说,将责任一步一步传下去,这就是责任,想到这个我们可以相当击鼓传花,这个是为了方便记忆,另外就是我们在项目中经常用到的审批流程等这一类的场景时我们就可以考 ...

  2. php 23种设计模式 - 责任链模式

    责任链模式 责任链模式(Chain of Responsibility Pattern)为请求创建了一个接收者对象的链.这种模式给予请求的类型,对请求的发送者和接收者进行解耦.这种类型的设计模式属于行 ...

  3. [工作中的设计模式]责任链模式chain

    一.模式解析 责任链模式是一种对象的行为模式.在责任链模式里,很多对象由每一个对象对其下家的引用而连接起来形成一条链.请求在这个链上传递,直到链上的某一个对象决定处理此请求.发出这个请求的客户端并不知 ...

  4. C#设计模式-责任链模式(Chain of Responsibility Pattern)

    引子 一个事件需要经过多个对象处理是一个挺常见的场景,譬如采购审批流程,请假流程,软件开发中的异常处理流程,web请求处理流程等各种各样的流程,可以考虑使用责任链模式来实现.现在以请假流程为例,一般公 ...

  5. 设计模式-责任链模式Chain of Responsibility)

    一.定义 职责链模式是一种对象的行为模式.在职责链模式里,很多对象由每一个对象对其下家的引用而连接起来形成一条链.请求在这个链上传递,直到链上的某一个对象决定处理此请求.发出这个请求的客户端并不知道链 ...

  6. 24种设计模式--中介者模式【Mediator Pattern】

    各位好,大家都是来自五湖四海,都要生存,于是都找了个靠山——公司,给你发薪水的地方,那公司就要想尽办法盈利赚钱,盈利方法则不尽相同,但是作为公司都有相同三个环节:采购.销售和库存,这个怎么说呢?比如一 ...

  7. 24种设计模式--多例模式【Multition Pattern】

    这种情况有没有?有!大点声,有没有?有,是,确实有,就出现在明朝,那三国期间的算不算,不算,各自称帝,各有各的地盘,国号不同.大家还 记得那首诗<石灰吟>吗?作者是谁?于谦,他是被谁杀死的 ...

  8. 二十四种设计模式:责任链模式(Chain of Responsibility Pattern)

    责任链模式(Chain of Responsibility Pattern) 介绍为解除请求的发送者和接收者之间耦合,而使多个对象都有机会处理这个请求.将这些对象连成一条链,并沿着这条链传递该请求,直 ...

  9. 乐在其中设计模式(C#) - 责任链模式(Chain of Responsibility Pattern)

    原文:乐在其中设计模式(C#) - 责任链模式(Chain of Responsibility Pattern) [索引页][源码下载] 乐在其中设计模式(C#) - 责任链模式(Chain of R ...

随机推荐

  1. SSDT – Error SQL70001 This statement is not recognized in this context-摘自网络

    March 28, 2013 — arcanecode One of the most common errors I get asked about when using SQL Server Da ...

  2. 每个android项目都应该使用的android 库

    http://blog.teamtreehouse.com/android-libraries-use-every-project A good developer knows to never re ...

  3. 注册表-恶意首页追踪之旅(IE不能改主页)

    恶意首页追踪之旅(先说下,360无法修复这个恶意首页) 话说,今天下了个扫站的工具,结果一不小心中了恶意广告! 中招后不停的乱下东西安装,360不停的在那弹出提示! 无语了,一个个卸载,把C:\win ...

  4. Oracle ABP(Autotask Background Process)

    ABP相当于自动任务与调度程序之间的中介,其主要作用是将自动任务转换成Autotask作业,供调度程序执行.同样重要的是,ABP还维护所有任务执行的历史记录.ABP将其专用资料档案库存储在sysaux ...

  5. 巧用TAG属性保存对象的指针

    指针的数据类型是整型,一个指针就是一个整型的数值. 所以凡整型的变量(这个整型的变量可以是声明在INI文件中,也可以是声明在函数中的)也好,对象的整型的属性也好,都可以用来存储一个指针. 但对象往往没 ...

  6. 浅谈js观察者模式

    观察者模式又叫发布订阅模式,它可以让多个观察者对象同时监听某一个主题对象,即在一个事件发生时,不同的对象迅速对其进行相应.就比如当又人闯红灯,不同的人对这件事迅速发起响应,当然这个比喻不太恰当,不过在 ...

  7. 前端javascript规范文档 (http://www.xuanfengge.com/category/web)

    说明:本文档为前端JS规范 一.规范目的 为提高团队协作效率,便于前端后期优化维护,输出高质量的文档. 二.基本准则 符合web标准,结构表现行为分离,兼容性优良.页面性能方面,代码要求简洁明了有序, ...

  8. eclipse调试的基本意义

    step into就是单步执行,遇到子函数就进入并且继续单步执行: step over是在单步执行时,在函数内遇到子函数时不会进入子函数内单步执行,而是将子函数整个执行完再停止,也就是把子函数整个作为 ...

  9. Android执行shell命令

    一.方法 /** * 执行一个shell命令,并返回字符串值 * * @param cmd * 命令名称&参数组成的数组(例如:{"/system/bin/cat", &q ...

  10. SilkTest天龙八部系列4-ChildWin

    一直觉得SilkTest的ChildWin不好理解,今天大致看了一下,其实它和DialogBox每啥区别,也是一种window类型.帮助里面说,典型的ChildWin就是文档窗口.在Windows上, ...