创建型(创建对象): 2 个 (工厂模式, 单例模式)
结构型: 6 个 (适配器模式, 组合模式, 装饰者模式, 代理模式, 外观模式, 桥梁模式)
行为型: 8 个 (中介者模式, 策略模式, 模板模式, 观察者模式, 迭代器模式, 责任链模式, 命令模式, 状态模式)
1. 工厂模式
提供一个创建类的统一接口.
目的: 每次创建类时, 只需要调用这个接口就可以了, 不用每次都需要写一次创建代码
上面是简单的工厂模式, 正常的工厂方法模式, 就是针对每个类, 都要创建一个工厂类. 但是他们可以实现共同的接口. (这种模式映射了之前我看的object c 的那本书), 一般用简单的工厂模式就可以了.
2. 单例模式
保证在内存中一个类只有一个实例存在, 并且提供一个访问该实例的全局访问点.
目的: 例如一个系统中可能存在多个打印任务, 但是只能一个正在工作的打印任务在内存中.
饿汉式: 类加载时, 就创建好了这个单例( 很饿, 所以要立刻吃, 立刻加载)
懒加载(懒汉式): 可以用的时候再加载 (吃的时候再说, 不是一开始就把饭做好)
如果 getInstance() 使用频率很高, 那肯定是饿汉式好.
利用 反射 破解单例模式
实际上, 在构造器函数内, 加一句话就可以防止反射破解单例
if (instance != null) {
throw new RuntimeException(); // 也就是多次多用构造器时, 抛出异常
}
通过反序列化的方式 构造多个对象, 破解单例
首先,通过序列化把对象写到硬盘上, 然后在把这个对象反序列化读回到程序中, 这时就不是之前的对象了.
如何防止序列化, 通过定义一个 readResolve() 方法 , 这个方法的作用是,在反序列化时, 如果这个类已经定义了实例, 直接返回这个实例就可以了, 不需要new一个新的了.
3. 适配器模式
将一个类的接口转换成客户希望的另一个接口.
目的: 比如我们去别的地方, 我们的插座的方向头是不一样的, 比如(中国, 德国 我出差去德国), 适配器需要满足以下要求:
(1) 必须符合德国标准的接口,否则的话还是没办法插到德国插座中
(2) 在调用上面实现的德标接口进行充电时,提供一种机制,将这个调用转到对国标接口的调用
这就要求:
(1) 适配器必须实现原有的旧的接口
(2) 适配器对象中持有对新接口的引用,当调用旧接口时,将这个调用委托给实现新接口的对象来处理,也就是在适配器对象中组合一个新接口
4. 组合模式
将对象组合成树型结构以表示“部分---整体”的层次结构
组合模式类似 “树”
component: 组合中对象的接口声明
composite: 树枝结点(有子节点)
leaf: 树叶结点(无子节点)
目的: 就是你想要这种层次关系的类时, 就可以使用.
例如: 各部门之间的层级关系
抽象接口类: package com.zyh.designpattern.composite; public abstract class Company { private String name; public Company(String name) { super(); this.name = name; } public Company(){} public String getName() { return name; } public void setName(String name) { this.name = name; } protected abstract void add(Company company); protected abstract void romove(Company company); protected abstract void display(int depth); } 枝结点类: package com.zyh.designpattern.composite; import java.util.ArrayList; import java.util.List; public class ConcreteCompany extends Company { private List cList; public ConcreteCompany() { cList = new ArrayList(); } public ConcreteCompany(String name) { super(name); cList = new ArrayList(); } @Override protected void add(Company company) { // TODO Auto-generated method stub cList.add(company); } @Override protected void display(int depth) { // TODO Auto-generated method stub StringBuilder sb = new StringBuilder(""); for (int i = 0; i < depth; i++) { sb.append("-"); } System.out.println(new String(sb) + this.getName()); for (Company c : cList) { c.display(depth + 2); } } @Override protected void romove(Company company) { // TODO Auto-generated method stub cList.remove(company); } } 两个叶结点类: -------------------------1---------------------------. package com.zyh.designpattern.composite; public class HRDepartment extends Company { public HRDepartment(String name) { super(name); } @Override protected void add(Company company) { } @Override protected void display(int depth) { // TODO Auto-generated method stub StringBuilder sb = new StringBuilder(""); for (int i = 0; i < depth; i++) { sb.append("-"); } System.out.println(new String(sb) + this.getName()); } @Override protected void romove(Company company) { } } ----------------2------------------- package com.zyh.designpattern.composite; public class FinanceDepartment extends Company { public FinanceDepartment(String name) { super(name); } @Override protected void add(Company company) { } @Override protected void display(int depth) { // TODO Auto-generated method stub StringBuilder sb = new StringBuilder(""); for (int i = 0; i < depth; i++) { sb.append("-"); } System.out.println(new String(sb) + this.getName()); } @Override protected void romove(Company company) { } } 客户端: package com.zyh.designpattern.composite; public class Client { public static void main(String[] args) { // TODO Auto-generated method stub Company root = new ConcreteCompany(); root.setName("北京总公司"); root.add(new HRDepartment("总公司人力资源部")); root.add(new FinanceDepartment("总公司财务部")); Company shandongCom = new ConcreteCompany("山东分公司"); shandongCom.add(new HRDepartment("山东分公司人力资源部")); shandongCom.add(new FinanceDepartment("山东分公司账务部")); Company zaozhuangCom = new ConcreteCompany("枣庄办事处"); zaozhuangCom.add(new FinanceDepartment("枣庄办事处财务部")); zaozhuangCom.add(new HRDepartment("枣庄办事处人力资源部")); Company jinanCom = new ConcreteCompany("济南办事处"); jinanCom.add(new FinanceDepartment("济南办事处财务部")); jinanCom.add(new HRDepartment("济南办事处人力资源部")); shandongCom.add(jinanCom); shandongCom.add(zaozhuangCom); Company huadongCom = new ConcreteCompany("上海华东分公司"); huadongCom.add(new HRDepartment("上海华东分公司人力资源部")); huadongCom.add(new FinanceDepartment("上海华东分公司账务部")); Company hangzhouCom = new ConcreteCompany("杭州办事处"); hangzhouCom.add(new FinanceDepartment("杭州办事处财务部")); hangzhouCom.add(new HRDepartment("杭州办事处人力资源部")); Company nanjingCom = new ConcreteCompany("南京办事处"); nanjingCom.add(new FinanceDepartment("南京办事处财务部")); nanjingCom.add(new HRDepartment("南京办事处人力资源部")); huadongCom.add(hangzhouCom); huadongCom.add(nanjingCom); root.add(shandongCom); root.add(huadongCom); root.display(0); } }
5. 装饰者模式
动态的给一个对象添加一些额外的职责
目的: 需要扩展一个类的功能, 或给一个类增加额外的功能, 例如: 比如生日蛋糕, 有一些级别的蛋糕的情况, 比如, 巧克力蛋糕, 草莓蛋糕等, 但是, 要想在蛋糕上单独加一些东西, 比如加一些花, 等等, 这样, 就可以将基本的蛋糕采用继承关系, 而装饰者有个抽象类, 那些加的花啊什么的, 都是继承这个装饰者类, 参考下边类图
6. 代理模式
为其他对象提供一种代理以控制对这个对象的访问
目的: 对对象访问进行控制, 比如西门庆找潘金莲,那潘金莲不好意思答复呀,咋办,找那个王婆做代理,表现在程序上时是这样的体现的
代码如下:
package com.yangguangfu.proxy; /** * * @author 阿福(trygf521@126.com)<br> *定义一种类型的女人,王婆和潘金莲都属于这个类型的女人 */ public interface KindWoman { //这种女人能做什么事情呢? public void makeEyesWithMan();//抛媚眼 public void happyWithMan();//和男人那个.... }
一种类型嘛,那肯定是接口,定义个潘金莲
package com.yangguangfu.proxy; /** * * @author 阿福(trygf521@126.com)<br> *定义一个潘金莲是什么样的人 */ public class PanJinLian implements KindWoman{ @Override public void happyWithMan() { System.out.println("潘金莲和男人在做那个..."); } @Override public void makeEyesWithMan() { System.out.println("潘金莲抛媚眼..."); } }
再定义个丑陋的王婆
package com.yangguangfu.proxy; /** * * @author 阿福(trygf521@126.com)<br> *王婆这个人老聪明了,她太老了,是个男人都看不上她, *但是她有智慧经验呀,他作为一类女人的代理! */ public class WangPo implements KindWoman { private KindWoman kindWoman; public WangPo(){ //默认的话是潘金莲的代理 this.kindWoman = new PanJinLian(); } //她可以是KindWomam的任何一个女人的代理,只要你是这一类型 public WangPo(KindWoman kindWoman){ this.kindWoman = kindWoman; } @Override public void happyWithMan() { //自己老了,干不了了,但可以叫年轻的代替。 this.kindWoman.happyWithMan(); } @Override public void makeEyesWithMan() { //王婆年纪大了,谁看她抛媚眼啊 this.kindWoman.makeEyesWithMan(); } }
两个女主角都上场了,该男主角了,定义个西门庆
package com.yangguangfu.proxy; /** * * @author 阿福(trygf521@126.com)<br> *水浒传是这样写的:西门庆被潘金莲用竹竿敲了一下,西门庆看痴迷了,被王婆看到了,就开始撮合两人好事,王婆作为潘金莲的代理人收了不少好处费,那我们假设一下: *如果没有王婆在中间牵线,这两个不要脸的能成事吗?难说得很! */ public class XiMenQiang { /** * @param args */ public static void main(String[] args) { WangPo wangPo; //把王婆叫出来 wangPo = new WangPo(); //然后西门庆说,我要和潘金莲Happy,然后王婆就安排了西门庆丢筷子哪出戏: wangPo.makeEyesWithMan(); //看到没有表面是王婆在做,其实爽的是潘金莲 wangPo.happyWithMan(); } }
7. 外观模式
为子系统中的一组接口提供一个一致的界面
比如: 不知道大家有没有比较过自己泡茶和去茶馆喝茶的区别,如果是自己泡茶需要自行准备茶叶、茶具和开水,如图1(A)所示,而去茶馆喝茶,最简单的方式就是跟茶馆服务员说想要一杯什么样的茶,是铁观音、碧螺春还是西湖龙井?正因为茶馆有服务员,顾客无须直接和茶叶、茶具、开水等交互,整个泡茶过程由服务员来完成,顾客只需与服务员交互即可,整个过程非常简单省事,如图1(B)所示
在软件开发中,有时候为了完成一项较为复杂的功能,一个客户类需要和多个业务类交互,而这些需要交互的业务类经常会作为一个整体出现,由于涉及到的类比较多,导致使用时代码较为复杂,此时,特别需要一个类似服务员一样的角色,由它来负责和多个业务类进行交互,而客户类只需与该类交互。外观模式通过引入一个新的外观类(Facade)来实现该功能,外观类充当了软件系统中的“服务员”,它为多个业务类的调用提供了一个统一的入口,简化了类与类之间的交互。在外观模式中,那些需要交互的业务类被称为子系统(Subsystem)。如果没有外观类,那么每个客户类需要和多个子系统之间进行复杂的交互,系统的耦合度将很大,如图2(A)所示;而引入外观类之后,客户类只需要直接与外观类交互,客户类与子系统之间原有的复杂引用关系由外观类来实现,从而降低了系统的耦合度,如图2(B)所示。
8. 桥梁模式
桥梁模式将抽象部分与它的实现部分分离
目的: 比如我们有一个画图程序 有2个图形(Circle Rectangle )和2种画图方法(Drawing1 Drawing2)图形可能会使用Drawing1来画图 也可能使用Drawing2来画图在这个画图程序中有两个可变因素 一个是图形的种类 有可能会增加新的图形 另一个是画图方法 可能会有Drawing3出现.
9. 中介者模式
中介者模式用一个中介对象封装一系列的对象交互
目的: 比如 在生活中,当电脑缺少了一块主板,那会怎么样?如果有人这样问我的话,我就会马上跳出来说“这电脑肯定报废了”,当然这不是重点。假如少了主板电脑还可以用的话,想想,里面的CPU、显卡、声卡、光驱、硬盘等等,不是就要我们自己用线把它们连起来。想想就觉得头疼,那么现在你觉得主板在电脑里扮演着什么角色呢?
例2:
Mediator:中介者接口。在里面定义了各个同事之间相互交互所需要的方法,可以是公共的方法,如Change方法,也可以是小范围的交互方法
ConcreteMediator:具体的中介者实现对象。它需要了解并为维护每个同事对象,并负责具体的协调各个同事对象的交互关系。
Colleague:同事类的定义,通常实现成为抽象类,主要负责约束同事对象的类型,并实现一些具体同事类之间的公共功能,比如,每个具体同事类都应该知道中介者对象,也就是每个同事对象都会持有中介者对象的引用,这个功能可定义在这个类中。
ConcreteColleague:具体的同事类,实现自己的业务,需要与其他同事对象交互时,就通知中介对象,中介对象会负责后续的交互。
10. 策略模式
策略模式定义一系列的算法,把它们一个个封装起来,并且使它们可以相互替换
比如:
刘备要到江东娶老婆了,走之前诸葛亮给赵云(伴郎)三个锦囊妙计,说是按天机拆开能解决棘手问题,嘿,还别说,真解决了大问题,搞到最后是周瑜陪了夫人又折兵,那咱们先看看这个场景是什么样子的。
先说说这个场景中的要素:三个妙计,一个锦囊,一个赵云,妙计是亮哥给的,妙计放在锦囊里,俗称就是锦囊妙计嘛,那赵云就是一个干活的人,从锦囊取出妙计,执行,然后获胜。用java程序怎么表现这些呢?
那我们先来看看图
三个妙计是同一类型的东西,那咱就写个接口:
package com.yangguangfu.strategy; /** * * @author trygf521@126.com:阿福 * 首先定义一个策略接口,这是诸葛亮老人家给赵云的三个锦囊妙计的接口。 */ public interface IStrategy { //每个锦囊妙计都是一个可执行的算法。 public void operate(); }
然后再写三个实现类,有三个妙计嘛:
妙计一:初到吴国:
package com.yangguangfu.strategy; /** * * @author trygf521@126.com:阿福 * 找乔国老帮忙,使孙权不能杀刘备。 */ public class BackDoor implements IStrategy { @Override public void operate() { System.out.println("找乔国老帮忙,让吴国太给孙权施加压力,使孙权不能杀刘备..."); } }
妙计二:求吴国太开个绿灯,放行:
package com.yangguangfu.strategy; /** * * @author trygf521@126.com:阿福 * 求吴国太开个绿灯。 */ public class GivenGreenLight implements IStrategy { @Override public void operate() { System.out.println("求吴国太开个绿灯,放行!"); } }
妙计三:孙夫人断后,挡住追兵:
package com.yangguangfu.strategy; /** * * @author trygf521@126.com:阿福 * 孙夫人断后,挡住追兵。 */ public class BlackEnemy implements IStrategy { @Override public void operate() { System.out.println("孙夫人断后,挡住追兵..."); } } 好了,大家看看,三个妙计是有了,那需要有个地方放妙计啊,放锦囊里:
package com.yangguangfu.strategy; /** * * @author trygf521@126.com:阿福 * */ public class Context { private IStrategy strategy; //构造函数,要你使用哪个妙计 public Context(IStrategy strategy){ this.strategy = strategy; } public void operate(){ this.strategy.operate(); } }
然后就是赵云雄赳赳的揣着三个锦囊,拉着已步入老年行列,还想着娶纯情少女的,色咪咪的刘备老爷子去入赘了,嗨,还别说,亮哥的三个妙计还真不错,瞧瞧:
package com.yangguangfu.strategy; public class ZhaoYun { /** * 赵云出场了,他根据诸葛亮给他的交代,依次拆开妙计 */ public static void main(String[] args) { Context context; //刚到吴国的时候拆开第一个 System.out.println("----------刚刚到吴国的时候拆开第一个---------------"); context = new Context(new BackDoor()); context.operate();//拆开执行 System.out.println(" "); //当刘备乐不思蜀时,拆开第二个 System.out.println("----------刘备乐不思蜀,拆第二个了---------------"); context = new Context(new GivenGreenLight()); context.operate();//拆开执行 System.out.println(" "); //孙权的小追兵了,咋办?拆开第三个锦囊 System.out.println("----------孙权的小追兵了,咋办?拆开第三个锦囊---------------"); context = new Context(new BlackEnemy()); context.operate();//拆开执行 System.out.println(" "); } }
11. 模板模式
定义一个操作中的算法骨架, 而将一些步骤延迟到子类中
个人感觉是定义一套流程”即算法骨架”, 置于骨架的内容, 要到实现时, 会有不同
比如: 我们使用冲泡咖啡和冲泡茶的例子
加工流程:
咖啡冲泡法:1.把水煮沸、2.用沸水冲泡咖啡、3.把咖啡倒进杯子、4.加糖和牛奶
茶冲泡法: 1.把水煮沸、2.用沸水冲泡茶叶、3.把 茶 倒进杯子、4.加蜂蜜
实践步骤:
1>创建一个模板(抽象)类:Beverage(饮料) 这里包含”骨架”
package com.kaishengit.beverage; public abstract class Beverage { /** * 冲泡咖啡或茶...流程 */ public final void create(){ boilWater();//把水煮沸 brew();//用沸水冲泡... pourInCup();//把...倒进杯子 addCoundiments();//加... } public abstract void addCoundiments(); public abstract void brew(); public void boilWater() { System.out.println("煮开水"); } public void pourInCup() { System.out.println("倒进杯子"); } }
2>创建一个咖啡类(Coffee)和茶(Tea)类,都继承Beverage抽象类
1.咖啡(Coffee)
package com.kaishengit.beverage; public class Coffee extends Beverage{ @Override public void addCoundiments() { System.out.println("添加糖和牛奶"); } @Override public void brew() { System.out.println("用水冲咖啡"); } }
2. 茶(Tea)
package com.kaishengit.beverage; public class Tea extends Beverage{ @Override public void addCoundiments() { System.out.println("添加蜂蜜"); } @Override public void brew() { System.out.println("用水冲茶"); } }
12. 观察者模式
定义了一种一对多的依赖关系,让多个观察者对象同时监听某一主题对象
模式中的角色
抽象主题(Subject):它把所有观察者对象的引用保存到一个聚集里,每个主题都可以有任何数量的观察者。抽象主题提供一个接口,可以增加和删除观察者对象。
具体主题(ConcreteSubject):将有关状态存入具体观察者对象;在具体主题内部状态改变时,给所有登记过的观察者发出通知。
抽象观察者(Observer):为所有的具体观察者定义一个接口,在得到主题通知时更新自己。
具体观察者(ConcreteObserver):实现抽象观察者角色所要求的更新接口,以便使本身的状态与主题状态协调
想想自己blog的气象站的例子(headfirst 设计模式中的例子)
13. 迭代器模式
迭代器模式提供一种方法顺序访问一个聚合对象中各个元素
迭代器角色(Iterator):迭代器角色负责定义访问和遍历元素的接口
具体迭代器角色(Concrete Iterator):具体迭代器角色要实现迭代器接口,并要记录遍历中的当前位置。
Aggregate (聚合): 聚合定义创建相应迭代器对象的接口
ConcreteAggregate (具体聚合): 具体聚合实现创建相应迭代器的接口,该操作返回ConcreteIterator的一个适当的实例
比如: 早期电视机, 按电视上按钮换台那种, 当我们换频道时, 重要的不是几频道, 而是节目内容.
在面向对象的软件设计中, 我们经常会遇到一类集合对象, 这类集合对象的内部结构可能有着各种各样的实现, 但是归结起来, 无非有两点是我们关心的: 一是集合内部的数据存储结构, 二是遍历这个集合内部的数据. Iterator 模式就是分离了集合对象的遍历行为.
首先有一个抽象的聚集, 所谓聚集就是数据的集合, 可以循环去访问它, 它只有一个方法 GetIterator()让子类去实现, 用来获得一个迭代器对象.
抽象迭代器: Iterator, 它用来访问聚集的类, 封装了一些方法, 通常会有 MoveNext(), CurrentItem(), First(), Next()
具体聚集 ConcreteList: 它实现了抽象聚集中的唯一方法, 同时再里面保存了一组数据
具体迭代器 ConcreteIterator: 具体迭代器, 它实现了迭代器中的4个方法, 在它的构造函数中需要接受一个具体聚集类型的参数.
14. 责任链模式
责任链模式使多个对象都有机会处理请求
抽象处理者 Handler: 定义出一个处理请求的接口,如果需要,接口可以定义出一个方法,以设定和返回对下家的引用。这个角色通常由一个抽象类或接口实现。
具体处理者(ConcreteHandler)角色:具体处理者接到请求后,可以选择将请求处理掉,或者将请求传给下家。由于具体处理者持有对下家的引用,因此,如果需要,具体处理者可以访问下家。
比如: 请假,审批的例子, 在公司里,如果你的请假时间小于0.5天,那么只需要向项目经理打声招呼就OK了, 如果超过了0.5天,但是还小于2天,那么就要去找人事部处理,当然,这就要扣工资了, 如果超过了2天,你就需要去找总经理了,工资当然也玩完了。那么,对于我们来说,这个流程就是这样的。
也就是这样一个过程,你需要和你的直接上级——项目经理去打交道,最终可能是项目经理给你回邮件,可能是人事部给你回邮件,也可能是总经理给你回邮件。内部的过程其实应该是个黑盒子,你并不知道内部的消息是如何处理的。你需要找到的,只是你想要第一个交付的对象而已.
下边是一个审批例子的具体代码.
抽象处理者角色
public abstract class Handler { /** * 持有下一个处理请求的对象 */ protected Handler successor = null; /** * 取值方法 */ public Handler getSuccessor() { return successor; } /** * 设置下一个处理请求的对象 */ public void setSuccessor(Handler successor) { this.successor = successor; } /** * 处理聚餐费用的申请 * @param user 申请人 * @param fee 申请的钱数 * @return 成功或失败的具体通知 */ public abstract String handleFeeRequest(String user , double fee);
具体处理者角色
项目经理
public class ProjectManager extends Handler { @Override public String handleFeeRequest(String user, double fee) { String str = ""; //项目经理权限比较小,只能在500以内 if(fee < 500) { //为了测试,简单点,只同意张三的请求 if("张三".equals(user)) { str = "成功:项目经理同意【" + user + "】的聚餐费用,金额为" + fee + "元"; }else { //其他人一律不同意 str = "失败:项目经理不同意【" + user + "】的聚餐费用,金额为" + fee + "元"; } }else { //超过500,继续传递给级别更高的人处理 if(getSuccessor() != null) { return getSuccessor().handleFeeRequest(user, fee); } } return str; } }
部门经理
public class DeptManager extends Handler { @Override public String handleFeeRequest(String user, double fee) { String str = ""; //部门经理的权限只能在1000以内 if(fee < 1000) { //为了测试,简单点,只同意张三的请求 if("张三".equals(user)) { str = "成功:部门经理同意【" + user + "】的聚餐费用,金额为" + fee + "元"; }else { //其他人一律不同意 str = "失败:部门经理不同意【" + user + "】的聚餐费用,金额为" + fee + "元"; } }else { //超过1000,继续传递给级别更高的人处理 if(getSuccessor() != null) { return getSuccessor().handleFeeRequest(user, fee); } } return str; } }
部长
public class GeneralManager extends Handler { @Override public String handleFeeRequest(String user, double fee) { String str = ""; //总经理的权限很大,只要请求到了这里,他都可以处理 if(fee >= 1000) { //为了测试,简单点,只同意张三的请求 if("张三".equals(user)) { str = "成功:总经理同意【" + user + "】的聚餐费用,金额为" + fee + "元"; }else { //其他人一律不同意 str = "失败:总经理不同意【" + user + "】的聚餐费用,金额为" + fee + "元"; } }else { //如果还有后继的处理对象,继续传递 if(getSuccessor() != null) { return getSuccessor().handleFeeRequest(user, fee); } } return str; } }
客户端类 (测试)
public class Client { public static void main(String[] args) { //先要组装责任链 Handler h1 = new GeneralManager(); Handler h2 = new DeptManager(); Handler h3 = new ProjectManager(); h3.setSuccessor(h2); h2.setSuccessor(h1); //开始测试 String test1 = h3.handleFeeRequest("张三", 300); System.out.println("test1 = " + test1); String test2 = h3.handleFeeRequest("李四", 300); System.out.println("test2 = " + test2); System.out.println("---------------------------------------"); String test3 = h3.handleFeeRequest("张三", 700); System.out.println("test3 = " + test3); String test4 = h3.handleFeeRequest("李四", 700); System.out.println("test4 = " + test4); System.out.println("---------------------------------------"); String test5 = h3.handleFeeRequest("张三", 1500); System.out.println("test5 = " + test5); String test6 = h3.handleFeeRequest("李四", 1500); System.out.println("test6 = " + test6); } }
输出结果:
15. 命令模式
将一个请求封装成为一个对象, 使可以用不同的请求对客户进行参数化
命令角色(Command):声明执行操作的接口。有java接口或者抽象类来实现。
具体命令角色(Concrete Command):将一个接收者对象绑定于一个动作;调用接收者相应的操作,以实现命令角色声明的执行操作的接口
客户角色(Client):创建一个具体命令对象(并可以设定它的接收者
请求者角色(Invoker):调用命令对象执行这个请求
接收者角色(Receiver):知道如何实施与执行一个请求相关的操作。任何类都可能作为一个接收者
比如: 电视机遥控器
电视机是请求的接收者Receiver,遥控器是请求的发送者Invoker, 遥控器上有一些按钮,不同的按钮对应电视机的不同操作Command. 抽象命令角色由一个命令接口来扮演, 有三个具体的命令类实现了抽象命令接口,这三个具体命令类分别代表三种操作:打开电视机、关闭电视机和切换频道
代码如下:
public interface Command { public void execute(); } public class ConcreteCommand implements Command { private Receiver receiver = null; private String state; public ConcreteCommand(Receiver receiver){ this.receiver = receiver; } public void execute() { receiver.action(); } } public class Receiver { public void action(){ //真正执行命令操作的功能代码 } } public class Invoker { private Command command = null; public void setCommand(Command command) { this.command = command; } public void runCommand() { command.execute(); } } public class Client { public void assemble(){ //创建接收者 Receiver receiver = new Receiver(); //创建命令对象,设定它的接收者 Command command = new ConcreteCommand(receiver); //创建Invoker,把命令对象设置进去 Invoker invoker = new Invoker(); invoker.setCommand(command); } }
模拟电视机换台的代码:
下面给个例子,是模拟对电视机的操作有开机、关机、换台命令。代码如下 //命令接收者 public class Tv { public int currentChannel = 0; public void turnOn() { System.out.println("The televisino is on."); } public void turnOff() { System.out.println("The television is off."); } public void changeChannel(int channel) { this.currentChannel = channel; System.out.println("Now TV channel is " + channel); } } //执行命令的接口 public interface Command { void execute(); } //开机命令 public class CommandOn implements Command { private Tv myTv; public CommandOn(Tv tv) { myTv = tv; } public void execute() { myTv.turnOn(); } } //关机命令 public class CommandOff implements Command { private Tv myTv; public CommandOff(Tv tv) { myTv = tv; } public void execute() { myTv.turnOff(); } } //频道切换命令 public class CommandChange implements Command { private Tv myTv; private int channel; public CommandChange(Tv tv, int channel) { myTv = tv; this.channel = channel; } public void execute() { myTv.changeChannel(channel); } } //可以看作是遥控器吧 public class Control { private Command onCommand, offCommand, changeChannel; public Control(Command on, Command off, Command channel) { onCommand = on; offCommand = off; changeChannel = channel; } public void turnOn() { onCommand.execute(); } public void turnOff() { offCommand.execute(); } public void changeChannel() { changeChannel.execute(); } } //测试类 public class Client { public static void main(String[] args) { // 命令接收者 Tv myTv = new Tv(); // 开机命令 CommandOn on = new CommandOn(myTv); // 关机命令 CommandOff off = new CommandOff(myTv); // 频道切换命令 CommandChange channel = new CommandChange(myTv, 2); // 命令控制对象 Control control = new Control(on, off, channel); // 开机 control.turnOn(); // 切换频道 control.changeChannel(); // 关机 control.turnOff(); } } 执行结果为: The televisino is on. Now TV channel is 2 The television is off.
16. 状态模式
状态模式容许一个对象在其内部状态改变时改变它的行为
上下文环境(Context):它定义了客户程序需要的接口并维护一个具体状态角色的实例,将与状态相关的操作委托给当前的Concrete State对象来处理.
抽象状态(State):定义一个接口以封装使用上下文环境的的一个特定状态相关的行为
具体状态(Concrete State):实现抽象状态定义的接口
举例:
电灯有两个状态,开(亮)与关(不亮),下面就用状态模式来实现对电灯的控制
/// <summary> /// 电灯类,对应模式中的Context类 /// </summary> public class Light { private LightState state; public Light(LightState state) { this.state = state; } /// <summary> /// 按下电灯开关 /// </summary> public void PressSwich() { state.PressSwich(this); } public LightState State { get { return state; } set { state = value; } } } /// <summary> /// 抽象的电灯状态类,相当于State类 /// </summary> public abstract class LightState { public abstract void PressSwich(Light light); } /// <summary> /// 具体状态类, 开 /// </summary> public class On : LightState { /// <summary> /// 在开状态下,按下开关则切换到关的状态。 /// </summary> /// <param name="light"></param> public override void PressSwich(Light light) { Console.WriteLine("Turn off the light."); light.State = new Off(); } } /// <summary> /// 具体状态类,关 /// </summary> public class Off: LightState { /// <summary> /// 在关状态下,按下开关则打开电灯。 /// </summary> /// <param name="light"></param> public override void PressSwich(Light light) { Console.WriteLine("Turn on the light."); light.State = new On(); } }
客户端代码
class Program { static void Main(string[] args) { // 初始化电灯,原始状态为关 Light light = new Light(new Off()); // 第一次按下开关,打开电灯 light.PressSwich(); // 第二次按下开关,关闭电灯 light.PressSwich(); Console.Read(); } }