这些设计模式提供了一种在建立对象的同时隐藏建立逻辑的方式,而不是使用新的运算符直接实例化对象。这使得程序在判断针对某个给定实例须要建立哪些对象时更加灵活。算法
这些设计模式关注类和对象的组合。继承的概念被用来组合接口和定义组合对象得到新功能的方式。编程
这些设计模式特别关注对象之间的通讯。设计模式
将一个类的接口转换成客户但愿的另一个接口。Adapter模式使得本来因为接口不兼容而不能一块儿工做的那些类能够在一块儿工做。
咱们用图来形象的解释这一律念:微信
这里的重点在于,老接口有特殊功能,咱们不忍舍弃,好比只有欧洲的插头(老接口)能从插座里得到电,没有电咱们过不下去。这个功能咱们没法舍弃
为了继续享受这个特殊功能,咱们使用适配器模式,让咱们手中的美国的插头(新接口),拥有老接口的能力。ide
例如一个美国人说英语,一个中国人说中文,为了跟美国人作生意,说英文这个功能咱们没法舍弃,可是咱们是中国人,天生不会说英文。因而二者想要交流,就须要一个适配器,来充当沟通二者的工做。如今,咱们但愿让一个能说中国话的个体(实现说中文的接口的类),开口说英文。函数
适配器有两种主要的实现,咱们先看第一种——类适配器测试
// 被适配类,已存在的、具备还有用处的特殊功能、但不符合咱们既有的标准接口的类 //——本例中即为一个会说f**k的美国人(你能够看做这个美国人实现了说英文的接口,不过这个可有可无,省略),他说的话咱们听不懂 class American{ public void speak() { System.out.println("f**k"); } }
// 目标接口,或称为标准接口 ——这里是一个说中文能力的接口,他定义了方法“说话”。 interface SpeakChinese { public void shuoHua(); }
// 具体目标类,只提供普通功能 ——这里咱们的具体实现是一个中国人类,他实现了说中国话的接口 class Chinese implements SpeakChinese { public void shuoHua() { System.out.println("敲里吗"); } }
// 适配器类,继承了被适配类,同时实现标准接口 ——如今咱们以为,那个美国人说的四字真言好拽哦,我也要学会,因而咱们定义了适配器 class Adapter extends American implements SpeakChinese { public void shuoHua() { super.speak(); } }
如今咱们定义一个laoWang,老王是一个Chinese,他会说话这个方法。
而后再定义一个适配器,看看适配器能不能用中文的说话方法,说出英文来。ui
// 测试类public class Client { public static void main(String[] args) { // 使用普通功能类 SpeakChinese laoWang= new Chinese(); laoWang.shuoHua(); // 使用特殊功能类,即适配类 SpeakChinese adapter = new Adapter(); adapter.shuoHua(); } }
测试结果:this
敲里吗 f**k
很棒,如今用了适配器,适配器用说中文的方式,说出了这句著名的英文,如今咱们迂回获得了说这四个字母的能力,能够去找外国友人交流感情了。spa
另一种适配器模式是对象适配器,它不是使用多继承或继承再实现的方式,而是使用直接关联,或者称为委托的方式。
其余目标类和被适配类都同样,就是适配器类的定义方式有所不一样:
// 适配器类,直接关联被适配类,同时实现标准接口 class Adapter implements SpeakChinese { // 直接关联被适配类 private American american; // 能够经过构造函数传入具体须要适配的被适配类对象 public Adapter (American american) { this.american = american; } public void shuoHua() { // 这里是使用委托的方式完成特殊功能 this.american.speak(); } }
在这里,咱们为了更灵活一点,定义了一个加州人,加州人和外面那些妖艳贱货不同,他们比较优雅,通常喜欢说hello。
class Californian extends American{ public void speak() { System.out.println("hello"); } }
public class Client { public static void main(String[] args) { // 使用普通功能类 SpeakChinese laoWang = new Chinese(); laoWang.shuoHua(); // 使用特殊功能类,即适配类, // 须要先建立一个被适配类的对象做为参数 American tom = new Californian(){} Target adapter = new Adapter(tom); adapter.shuoHua(); } }
测试结果
敲里吗 hello
一样的,咱们用适配器得到了像加州人那样优雅的说英文的能力。对象适配器相对于类适配器来讲比较灵活,咱们能够复用这个适配器,经过传参的不一样,获得德克萨斯人,弗吉尼亚人,佛罗里达人的说话方式。
模式总结
首先咱们理解策略的概念,策略就是一组算法,一种实现。策略模式定义了一系列的算法,并将每个算法封装起来,并且使他们能够相互替换,让算法独立于使用它的客户而独立变化。
例如足智多谋的诸葛亮,他的每一个锦囊,就是一个策略,如今诸葛亮给了关羽三个锦囊——锦囊A,锦囊B,锦囊C,告诉关羽若是敌军数量在一万到三万之内,打开锦囊A;敌军数量在三万到五万之间,打开锦囊B;还更多的话,打开锦囊C。
//抽象策略类 锦囊接口 public interface JinNang { /** * 策略方法 打开锦囊 */ public void openJinNang(); }
//具体策略类 锦囊A public class JinNangA implements JinNang { @Override public void openJinNang(Integer enermyNum) { System.out.println("朝敌军使用抛掷粪便攻击,杀敌20%!伤敌数量为:"+enermyNum*0.2); } } //具体策略类 锦囊B public class JinNangB implements JinNang { @Override public void openJinNang(Integer enermyNum) { System.out.println("朝敌军播放难忘今宵以瓦解敌军意志,杀敌50%!伤敌数量为:"+enermyNum*0.5); } } //具体策略类 锦囊C public class JinNangC implements JinNang { @Override public void openJinNang(Integer enermyNum) { System.out.println("丫的还不快跑!?"); } }
//环境角色类--关羽 public class GuanYu{ //持有一个具体策略的对象 private JinNang jinNang; /** * 策略方法 */ public void fight(Integer enermyNum){ if (enermyNum >10000&enermyNum<30000){ jinNang=new JinNangA(); } else if (enermyNum >30000&enermyNum<50000){ jinNang=new JinNangB(); } else{ jinNang=new JinNangC(); } jinNang.openJinNang(enermyNum); } }
好的,如今咱们的关羽跨上赤兔马,拎起青龙刀,来到了阵前,对面分别出动了两个师,四个师,十个师的兵力干他!即使如此,咱们的小英雄也A了上去!
public static void main(String[] args) { GuanYu guanYu = new GuanYu(); guanYu.fight(20000); guanYu.fight(40000); guanYu.fight(100000); }
测试结果
显而易见,测试结果是:
朝敌军使用抛掷粪便攻击,杀敌20%!伤敌数量为:4000.0 朝敌军播放难忘今宵以瓦解敌军意志,杀敌50%!伤敌数量为:20000.0 丫的还不快跑!?
外观模式(Facade Pattern)又称为门面模式,它为系统中的一组接口提供一个一致的界面,此模式定义了一个高层接口,这个接口使得子系统更加容易使用。该模式能够隐藏系统的复杂性,提供了客户端请求的简化方法和对现有系统类方法的委托调用。
蜀汉集团总经理诸葛亮为了光复中原,推出了“三个臭皮匠”阵法,由关羽张飞赵云压阵,在砍人的时候充当蜀军的门面。因而在群P的时候,对于他们的客户(敌人)来讲,和外观(阵法)交互(打架)并不须要知道他们内在的细节,许多繁琐的逻辑,已经被门面封装了。
咱们先来定义三个子系统:关张赵
/** * 子系统关羽 */ public class GuanYu { //剪刀 public void jianDao(){ System.out.println("关羽出剪刀"); } public void shiTou(){ System.out.println("关羽出石头"); } public void bu(){ System.out.println("关羽出布"); } } /** * 子系统赵云 */ public class ZhaoYun{ //剪刀 public void jianDao(){ System.out.println("赵云出剪刀"); } public void shiTou(){ System.out.println("赵云出石头"); } public void bu(){ System.out.println("赵云出布"); } } /** * 子系统张飞 */ public class ZhangFei { //剪刀 public void jianDao(){ System.out.println("张飞出剪刀"); } public void shiTou(){ System.out.println("张飞出石头"); } public void bu(){ System.out.println("张飞出布"); } }
接下来定义统一的外观类——三个臭皮匠阵法,这个阵法有三个绝技,青龙腾,白龙腾和黑龙腾,至于技能内到底怎么实现的,大家这些凡人就不要在乎了,总之发动起来,天上都是龙,大家只要负责喊666就能够了。
public class ThreeChouPiJiang{ private GuanYu guanYu; private ZhangFei zhangFei; private ZhaoYun zhaoYun; ThreeChouPiJiang(){ guanYu =new GuanYu(); zhangFei = new ZhangFei(); zhaoYun = new ZhaoYun(); } //青龙腾 public void qingLongTeng(){ zhangFei.bu(); zhaoYun.bu(); guanYu.shiTou(); System.out.println("青龙腾:关羽输了,关羽出去砍人;"); System.out.println("BO~BO~BO~经费燃烧中~ ============="); } //黑龙腾 public void heiLongTeng(){ guanYu.bu(); zhaoYun.bu(); zhangFei.shiTou(); System.out.println("黑龙腾:张飞输了,张飞出去砍人;"); System.out.println("BO~BO~BO~经费燃烧中~ ============="); } //白龙腾 public void baiLongTeng(){ guanYu.bu(); zhangFei.bu(); zhaoYun.shiTou(); System.out.println(":赵云输了,赵云出去砍人;"); System.out.println("BO~BO~BO~经费燃烧中~ ============="); } }
好了,咱们的阵法已经定义好了,如今诸葛亮意气风发,决定要北伐中原,咱们的三个臭皮匠阵法,开始发挥威力:
public static void main(String[] args) { ThreeChouPiJiang threeChouPiJiang = new ThreeChouPiJiang(); ThreeChouPiJiang threeChouPiJiang = new ThreeChouPiJiang(); threeChouPiJiang.baiLongTeng(); threeChouPiJiang.qingLongTeng(); threeChouPiJiang.heiLongTeng(); }
测试结果:
关羽出布 张飞出布 赵云出石头 白龙腾:赵云输了,赵云出去砍人; BO~BO~BO~经费燃烧中~ ============= 张飞出布 赵云出布 关羽出石头 青龙腾:关羽输了,关羽出去砍人; BO~BO~BO~经费燃烧中~ ============= 关羽出布 赵云出布 张飞出石头 黑龙腾:张飞输了,张飞出去砍人; BO~BO~BO~经费燃烧中~ =============
威力果真是十分惊人啊!对于敌人而言,他们只知道三个臭皮匠阵法使用了绝招,根本不会知道绝招内部竟然是这三个货用剪刀石头布搞出来的。在顶级特效的加持下,这个门面仍是十分整洁十分威风十分唬人的。
外观模式的目的不是给予子系统添加新的功能接口,而是为了让外部减小与子系统内多个模块的交互,松散耦合,从而让外部可以更简单地使用子系统。
外观模式的本质是:封装交互,简化调用。
在对象之间定义了一对多的依赖,这样一来,当一个对象改变状态,依赖它的对象会收到通知并自动更新。
简单来讲,其实就是发布订阅模式,发布者发布信息,订阅者获取信息,订阅了就能收到信息,没订阅就收不到信息。
例如微信公众号服务,不定时发布一些消息,关注公众号就能够收到推送消息,取消关注就收不到推送消息。
/*** * 抽象被观察者接口 * 声明了添加、删除、通知观察者方法 */ public interface Observerable { public void registerObserver(Observer o);//新增订阅人 public void removeObserver(Observer o);//删除订阅人 public void notifyObserver();//发布消息 }
/*** * 抽象观察者 * 定义了一个update()方法,当被观察者调用notifyObservers()方法时,观察者的update()方法会被回调。 */ public interface Observer { public void update(String message);//更新消息 }
/** * 被观察者,也就是微信公众号服务 * 实现了Observerable接口,对Observerable接口的三个方法进行了具体实现 */ public class WechatServer implements Observerable { //注意到这个List集合的泛型参数为Observer接口,设计原则:面向接口编程而不是面向实现编程 private List<Observer> list; private String message; public WechatServer() { list = new ArrayList<Observer>(); } @Override public void registerObserver(Observer o) { list.add(o); } @Override public void removeObserver(Observer o) { if(!list.isEmpty()) list.remove(o); } //遍历通知 @Override public void notifyObserver() { for(int i = 0; i < list.size(); i++) { Observer oserver = list.get(i); oserver.update(message); } } public void setInfomation(String s) { this.message = s; System.out.println("微信服务更新消息: " + s); //消息更新,通知全部观察者 notifyObserver(); } }
/** * 观察者 * 实现了update方法 */ public class User implements Observer { private String name; private String message; public User(String name) { this.name = name; } @Override public void update(String message) { this.message = message; read(); } public void read() { System.out.println(name + " 收到推送消息: " + message); } }
首先注册了三个用户,ZhangSan、LiSi、WangWu。公众号发布了一条消息"PHP是世界上最好用的语言!",三个用户都收到了消息。
用户ZhangSan看到消息后颇为震惊,果断取消订阅,这时公众号又推送了一条消息,此时用户ZhangSan已经收不到消息,其余用户
仍是正常能收到推送消息。
public class Test { public static void main(String[] args) { WechatServer server = new WechatServer(); Observer userZhang = new User("ZhangSan"); Observer userLi = new User("LiSi"); Observer userWang = new User("WangWu"); server.registerObserver(userZhang); server.registerObserver(userLi); server.registerObserver(userWang); server.setInfomation("PHP是世界上最好用的语言!"); System.out.println("----------------------------------------------"); server.removeObserver(userZhang); server.setInfomation("JAVA是世界上最好用的语言!"); } }
测试结果:
使多个对象都有机会处理同一个请求,从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。
为完成同一个请求,若是存在多个请求处理器以及未知请求处理器个数或者请求处理器可动态配置的状况下,能够考虑使用责任链模式。
适用于: 链条式处理事情。工做流程化、消息处理流程化、事物流程化;
圣斗士星矢,五小强们勇闯黄金十二宫,咱们能够把这十二宫,当作是十二个处理者,他们用一条链串起来。
咱们先来定义一个抽象的黄金圣斗士的抽象类:
public interface GoldenWarrior { void fight(String xiaoQiangName,String response,GoldenWarriorChain chain); }
咱们定义一个白羊座圣斗士:
public class AriesWorrior implements GoldenWarrior{ @Override public void fight(String request, String response, GoldenWarriorChain chain) { System.out.println(request+"fight with AriesWorrior,AriesWorrior lose"); chain.fight(request, response, chain); System.out.println(response+" reback to AriesWorrior here!"); } }
再来定义一个狮子座圣斗士
public class LeoWorrior implements GoldenWarrior{ @Override public void fight(String request, String response, GoldenWarriorChain chain) { System.out.println(request+"fight with LeoWorrior,LeoWorrior lose"); chain.fight(request, response, chain); System.out.println(response+" reback to LeoWorrior here!"); } }
而后,是咱们的责任链对象,或者说是咱们例子里面的 十二宫(其实咱们就实现了两宫)对象
public class GoldenWarriorChain implements GoldenWarrior{ //十二宫的圣斗士们 private List<GoldenWarrior> goldenWarriors=new ArrayList<GoldenWarrior>(); //目前到哪一个宫了 private int index; public GoldenWarriorChain addWorrior(GoldenWarrior warrior){ this.goldenWarriors.add(warrior); return this; } public void fight(String request, String response,GoldenWarriorChain chain) { if(index==goldenWarriors.size()) return;//若是链条里没有filter或是链条里的filter都调用过了(有点象递归) goldenWarriors.get(index++).fight(request, response, chain); } }
public static void main(String[] a){ GoldenWarriorChain goldenWarriorChain = new GoldenWarriorChain(); goldenWarriorChain.addWorrior(new LeoWorrior()); goldenWarriorChain.addWorrior(new AriesWorrior()); goldenWarriorChain.fight("星矢","",goldenWarriorChain); }
星矢fight with LeoWorrior,LeoWorrior lose 星矢fight with AriesWorrior,AriesWorrior lose reback to AriesWorrior here! reback to LeoWorrior here!
由于String是不可变对象,故而,response和request没能在调用后被自动传递至下一层,或者递归后被自动带回上一层(实际上咱们也没有对它进行过处理,只是打印出来而已),若是response和request是对象的话,上层对象就能获得下层的结果,不过咱们的核心在不在这,无足轻重。
1。责任的分担。每一个类只须要处理本身该处理的工做(不应处理的传递给下一个对象完成),明确各种的责任范围,符合类的最小封装原则。
2。能够根据须要自由组合工做流程。如工做流程发生变化,能够经过从新分配对象链即可适应新的工做流程。
3。类与类之间能够以松耦合的形式加以组织。
由于处理时以链的形式在对象间传递消息,根据实现方式不一样,有可能会影响处理的速度。