前言:html
设计模式是对你们实际工做中写的各类代码进行高层次抽象的总结,其中最出名的当属 Gang of Four (GoF) 的分类了,他们将设计模式分类为 23 种经典的模式,根据用途咱们又能够分为三大类,分别为建立型模式、结构型模式和行为型模式。是的,我不善于扯这些有的没的,仍是少点废话吧~~~java
有一些重要的设计原则在开篇和你们分享下,这些原则将贯通全文:算法
面向接口编程,而不是面向实现。这个很重要,也是优雅的、可扩展的代码的第一步,这就不须要多说了吧。数据库
职责单一原则。每一个类都应该只有一个单一的功能,而且该功能应该由这个类彻底封装起来。编程
对修改关闭,对扩展开放。对修改关闭是说,咱们辛辛苦苦加班写出来的代码,该实现的功能和该修复的 bug 都完成了,别人可不能说改就改;对扩展开放就比较好理解了,也就是说在咱们写好的代码基础上,很容易实现扩展。1、设计模式入门:设计模式
1.设计模式是人们在面对同类型软件工程设计问题所总结出的一些有用经验。模式不是代码,而是某类问题的通用设计解决方案
2.设计模式的本质目的是使软件工程在维护性、扩展性、变化性、复杂度方面成O(N)
3.OOP是原则,设计模式是具体方法、工具 浏览器
首先咱们看下各个模式之间的关系图,下面这张图是网上比较典型的一个类图关系:安全
从上面的类图之间能够看出,学习设计模式或者说学懂彻底理解全部的设计模式仍是挺难的,只能说不断的重复学习,不断的去领悟才是惟一的方法,固然不排除有些人是天才看一篇就学会了,惋惜鄙人不是,因此必须不断重复学习来加深本身的理解。我的感受,单例、工厂、装饰者、观察者、代理模式使用的频率比较高;固然不是说其余模糊就不使用,只是我的的见解而已,o(* ̄︶ ̄*)o。服务器
学习设计模式,首先要学习的就是设计原则,所以我从设计原则来开始第一个节。网络
(一)、设计原则
1.单一职责
2.里氏替换原则 (Liskov Substitution Principle)
3.依赖倒置原则 (Dependence Inversion Principle)
4.接口隔离原则 (Interface Segregation Principle)
5.迪米特法则(最少知道原则) (Demeter Principle)
6.开闭原则(Open Close Principle
咱们用一幅图来讲明一下
详细请参考:www.cnblogs.com/pony1223/p/7594803.html
(二)、什么是设计模式
设计模式(Design pattern)是一套被反复使用、多数人知晓的、通过分类编目的、代码设计经验的总结。使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性。 毫无疑问,设计模式于己于他人于系统都是多赢的,设计模式使代码编制真正工程化,设计模式是软件工程的基石,如同大厦的一块块砖石同样。项目中合理的运用设计模式能够完美的解决不少问题,每种模式在如今中都有相应的原理来与之对应,每个模式描述了一个在咱们周围不断重复发生的问题,以及该问题的核心解决方案,这也是它能被普遍应用的缘由。简单说:
模式:在某些场景下,针对某类问题的某种通用的解决方案。
场景:项目所在的环境
问题:约束条件,项目目标等
解决方案:通用、可复用的设计,解决约束达到目标。
(三)、设计模式的三个分类
建立型模式:对象实例化的模式,建立型模式用于解耦对象的实例化过程。
结构型模式:把类或对象结合在一块儿造成一个更大的结构。
行为型模式:类和对象如何交互,及划分责任和算法。
以下图所示:
各分类中模式的关键点
单例模式:某个类只能有一个实例,提供一个全局的访问点。
简单工厂:一个工厂类根据传入的参量决定建立出那一种产品类的实例。
工厂方法:定义一个建立对象的接口,让子类决定实例化那个类。
抽象工厂:建立相关或依赖对象的家族,而无需明确指定具体类。
建造者模式:封装一个复杂对象的构建过程,并能够按步骤构造。
原型模式:经过复制现有的实例来建立新的实例。
适配器模式:将一个类的方法接口转换成客户但愿的另一个接口。
组合模式:将对象组合成树形结构以表示“”部分-总体“”的层次结构。
装饰模式:动态的给对象添加新的功能。
代理模式:为其余对象提供一个代理以便控制这个对象的访问。
亨元(蝇量)模式:经过共享技术来有效的支持大量细粒度的对象。
外观模式:对外提供一个统一的方法,来访问子系统中的一群接口。
桥接模式:将抽象部分和它的实现部分分离,使它们均可以独立的变化。
模板模式:定义一个算法结构,而将一些步骤延迟到子类实现。
解释器模式:给定一个语言,定义它的文法的一种表示,并定义一个解释器。
策略模式:定义一系列算法,把他们封装起来,而且使它们能够相互替换。
状态模式:容许一个对象在其对象内部状态改变时改变它的行为。
观察者模式:对象间的一对多的依赖关系。
备忘录模式:在不破坏封装的前提下,保持对象的内部状态。
中介者模式:用一个中介对象来封装一系列的对象交互。
命令模式:将命令请求封装为一个对象,使得能够用不一样的请求来进行参数化。
访问者模式:在不改变数据结构的前提下,增长做用于一组对象元素的新功能。
责任链模式:将请求的发送者和接收者解耦,使的多个对象都有处理这个请求的机会。
迭代器模式:一种遍历访问聚合对象中各个元素的方法,不暴露该对象的内部结构。
2、概说23种设计模式 :
1.单例模式
单例模式,它的定义就是确保某一个类只有一个实例,而且提供一个全局访问点。
单例模式具有典型的3个特色:一、只有一个实例。 二、自我实例化。 三、提供全局访问点。
所以当系统中只须要一个实例对象或者系统中只容许一个公共访问点,除了这个公共访问点外,不能经过其余访问点访问该实例时,可使用单例模式。
单例模式的主要优势就是节约系统资源、提升了系统效率,同时也可以严格控制客户对它的访问。也许就是由于系统中只有一个实例,这样就致使了单例类的职责太重,违背了“单一职责原则”,同时也没有抽象类,因此扩展起来有必定的困难。其UML结构图很是简单,就只有一个类,以下图:
懒汉式:
public class Singleton { /* 持有私有静态实例,防止被引用,此处赋值为null,目的是实现延迟加载 */ private static Singleton instance = null; /* 私有构造方法,防止被实例化 */ private Singleton() {} /* 1:懒汉式,静态工程方法,建立实例 */ public static Singleton getInstance() { if (instance == null) { instance = new Singleton(); } return instance; } }
调用:Singleton.getInstance().method();
双重线程检查模式:
public class SingletonInner { private static volatile SingletonInner sInst = null; // <<< 这里添加了 volatile /** * 私有的构造函数 */ private SingletonInner() {} public static SingletonInner getInstance() { SingletonInner inst = sInst; // <<< 在这里建立临时变量 if (inst == null) { synchronized (SingletonInner.class) { inst = sInst; if (inst == null) { inst = new SingletonInner(); sInst = inst; } } } return inst; // <<< 注意这里返回的是临时变量 } protected void method() { System.out.println("SingletonInner"); } }
调用:Singleton.getInstance().method();
2.工厂方法模式
做为抽象工厂模式的孪生兄弟,工厂方法模式定义了一个建立对象的接口,但由子类决定要实例化的类是哪个,也就是说工厂方法模式让实例化推迟到子类。
工厂方法模式很是符合“开闭原则”,当须要增长一个新的产品时,咱们只须要增长一个具体的产品类和与之对应的具体工厂便可,无须修改原有系统。同时在工厂方法模式中用户只须要知道生产产品的具体工厂便可,无须关系产品的建立过程,甚至连具体的产品类名称都不须要知道。虽然他很好的符合了“开闭原则”,可是因为每新增一个新产品时就须要增长两个类,这样势必会致使系统的复杂度增长。其UML结构图:
示例代码:
public class Factory{ //getClass 产生Sample 通常可以使用动态类装载装入类。 public static Sample creator(int which){ if (which==1) return new SampleA(); else if (which==2) return new SampleB(); } }
/抽象产品角色 public interface Moveable { void run(); } //具体产品角色 public class Plane implements Moveable { @Override public void run() { System.out.println("plane...."); } } //具体产品角色 public class Broom implements Moveable { @Override public void run() { System.out.println("broom....."); } } //抽象工厂 public abstract class VehicleFactory { abstract Moveable create(); } //具体工厂 public class PlaneFactory extends VehicleFactory{ public Moveable create() { return new Plane(); } } //具体工厂 public class BroomFactory extends VehicleFactory{ public Moveable create() { return new Broom(); } } //测试类 public class Test { public static void main(String[] args) { VehicleFactory factory = new BroomFactory(); Moveable m = factory.create(); m.run(); } }
3.抽象工厂模式
所谓抽象工厂模式就是提供一个接口,用于建立相关或者依赖对象的家族,而不须要明确指定具体类。他容许客户端使用抽象的接口来建立一组相关的产品,而不须要关系实际产出的具体产品是什么。这样一来,客户就能够从具体的产品中被解耦。它的优势是隔离了具体类的生成,使得客户端不须要知道什么被建立了,而缺点就在于新增新的行为会比较麻烦,由于当添加一个新的产品对象时,须要更加须要更改接口及其下全部子类。其UML结构图以下:
示例代码:
//抽象工厂类 public abstract class AbstractFactory { public abstract Vehicle createVehicle(); public abstract Weapon createWeapon(); public abstract Food createFood(); } //具体工厂类,其中Food,Vehicle,Weapon是抽象类, public class DefaultFactory extends AbstractFactory{ @Override public Food createFood() { return new Apple(); } @Override public Vehicle createVehicle() { return new Car(); } @Override public Weapon createWeapon() { return new AK47(); } } //测试类 public class Test { public static void main(String[] args) { AbstractFactory f = new DefaultFactory(); Vehicle v = f.createVehicle(); v.run(); Weapon w = f.createWeapon(); w.shoot(); Food a = f.createFood(); a.printName(); } }
4.建造者模式
对于建造者模式而已,它主要是将一个复杂对象的构建与表示分离,使得一样的构建过程能够建立不一样的表示。适用于那些产品对象的内部结构比较复杂。
建造者模式将复杂产品的构建过程封装分解在不一样的方法中,使得建立过程很是清晰,可以让咱们更加精确的控制复杂产品对象的建立过程,同时它隔离了复杂产品对象的建立和使用,使得相同的建立过程可以建立不一样的产品。可是若是某个产品的内部结构过于复杂,将会致使整个系统变得很是庞大,不利于控制,同时若几个产品之间存在较大的差别,则不适用建造者模式,毕竟这个世界上存在相同点大的两个产品并非不少,因此它的使用范围有限。其UML结构图:
如何使用??
首先假设一个复杂对象是由多个部件组成的,Builder模式是把复杂对象的建立和部件的建立分别开来,分别用Builder类和Director类来表示。
首先,须要一个接口,它定义如何建立复杂对象的各个部件:
public interface Builder { //建立部件A 好比建立汽车车轮void buildPartA(); //建立部件B 好比建立汽车方向盘void buildPartB(); //建立部件C 好比建立汽车发动机void buildPartC(); //返回最后组装成品结果 (返回最后装配好的汽车) //成品的组装过程不在这里进行,而是转移到下面的Director类中进行. //从而实现了解耦过程和部件 Product getResult(); }
用Director构建最后的复杂对象,而在上面Builder接口中封装的是如何建立一个个部件(复杂对象是由这些部件组成的),也就是说Director的内容是如何将部件最后组装成成品:
public class Director { private Builder builder; public Director( Builder builder ) { this.builder = builder; } // 将部件partA partB partC最后组成复杂对象 //这里是将车轮 方向盘和发动机组装成汽车的过程 public void construct() { builder.buildPartA(); builder.buildPartB(); builder.buildPartC(); } }
Builder的具体实现ConcreteBuilder:
public class ConcreteBuilder implements Builder { Part partA, partB, partC; public void buildPartA() { //这里是具体如何构建 } public void buildPartB() { //这里是具体如何构建 } public void buildPartC() { //这里是具体如何构建 } public Product getResult() { //返回最后组装成品结果 } }
复杂对象:产品Product:
public interface Product { }
复杂对象的部件:
public interface Part { }
咱们看看如何调用Builder模式:
ConcreteBuilder builder = new ConcreteBuilder(); Director director = new Director( builder ); director.construct(); Product product = builder.getResult();
5.观察者模式
基本概念:观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一主题对象。这个主题对象在状态发生变化时,会通知全部观察者对象,使它们可以自动更新本身。观察者模式又叫发布-订阅(Publish/Subscribe)模式。
UML结构图:
如何使用??
例如:老师有电话号码,学生须要知道老师的电话号码以便于在合适的时候拨打,在这样的组合中,老师就是一个被观察者(Subject),学生就是须要知道信息的观察者,当老师的电话号码发生改变时,学生获得通知,并更新相应的电话记录。
先建立一个Subject类: /** * Subject(目标,Subject): * 目标知道它的观察者。能够有任意多个观察者观察同一个目标。 * 提供注册和删除观察者对象的接口。 */ public interface Subject { public void attach(Observer mObserver); public void detach(Observer mObserver); public void notice(); }
建立Observer类:
/** * Observer(观察者,Observer): * 为那些在目标发生改变时须要得到通知的对象定义一个更新接口。 */ public interface Observer { public void update(); }
建立ConcreteSubject类:
/** * ConcreteSubject(具体目标,Teacher) * 将有关状态存入各ConcreteObserve对象。 * 当他的状态发生改变时,向他的各个观察者发出通知。 */ public class Teacher implements Subject{ private String phone; private Vector students; public Teacher(){ phone = ""; students = new Vector(); } @Override public void attach(Observer mObserver) { students.add(mObserver); } @Override public void detach(Observer mObserver) { students.remove(mObserver); } @Override public void notice() { for(int i=0;i<students.size();i++){ ((Observer)students.get(i)).update(); } } public String getPhone() { return phone; } public void setPhone(String phone) { this.phone = phone; notice(); } }
建立ConcreteObserver类:
/** * ConcreteObserver(具体观察者, Student): * 维护一个指向ConcreteSubject对象的引用。 * 存储有关状态,这些状态应与目标的状态保持一致。 * 实现Observer的更新接口以使自身状态与目标的状态保持一致。 */ public class Student implements Observer{ private String name; private String phone; private Teacher mTeacher; public Student(String name,Teacher t){ this.name = name; mTeacher = t; } public void show(){ System.out.println("Name:"+name+"\nTeacher'sphone:" + phone); } @Override public void update() { phone = mTeacher.getPhone(); } }
客户端测试:
/** * 观察者(Observer)模式测试类 */ public class ObserverClient { public static void main(String[] args) { Vector students = new Vector(); Teacher t = new Teacher(); for(int i= 0;i<10;i++){ Student st = new Student("Andy.Chen"+i,t); students.add(st); t.attach(st); } System.out.println("Welcome to Andy.Chen Blog!" +"\n" +"Observer Patterns." +"\n" +"-------------------------------"); t.setPhone("12345678"); for(int i=0;i<3;i++) ((Student)students.get(i)).show(); t.setPhone("87654321"); for(int i=0;i<3;i++) ((Student)students.get(i)).show(); } }
程序运行结果以下:
Welcome to Andy.Chen Blog! Observer Patterns. ------------------------------- Name:Andy.Chen0 Teacher'sphone:12345678 Name:Andy.Chen1 Teacher'sphone:12345678 Name:Andy.Chen2 Teacher'sphone:12345678 Name:Andy.Chen0 Teacher'sphone:87654321 Name:Andy.Chen1 Teacher'sphone:87654321 Name:Andy.Chen2 Teacher'sphone:87654321
六、适配器(Adapter)模式
基本概念:适配器模式把一个类的接口变换成客户端所期待的另外一种接口,从而使本来因接口不匹配而没法在一块儿工做的两个类可以在一块儿工做。
适配器模式的用途
用电器作例子,笔记本电脑的插头通常都是三相的,即除了阳极、阴极外,还有一个地极。而有些地方的电源插座却只有两极,没有地极。电源插座与笔记本电脑的电源插头不匹配使得笔记本电脑没法使用。这时候一个三相到两相的转换器(适配器)就能解决此问题,而这正像是本模式所作的事情。
适配器模式的结构
适配器模式有类的适配器模式
和对象的适配器模式
两种不一样的形式。
示例代码:
public interface Target { /** * 这是源类Adaptee也有的方法 */ public void sampleOperation1(); /** * 这是源类Adapteee没有的方法 */ public void sampleOperation2(); }
上面给出的是目标角色的源代码,这个角色是以一个Java接口的形式实现的。能够看出,这个接口声明了两个方法:sampleOperation1()和sampleOperation2()。而源角色Adaptee是一个具体类,它有一个sampleOperation1()方法,可是没有sampleOperation2()方法。
public class Adaptee { public void sampleOperation1(){} }
适配器角色Adapter扩展了Adaptee,同时又实现了目标(Target)接口。因为Adaptee没有提供sampleOperation2()方法,而目标接口又要求这个方法,所以适配器角色Adapter实现了这个方法。
public class Adapter extends Adaptee implements Target { /** * 因为源类Adaptee没有方法sampleOperation2() * 所以适配器补充上这个方法 */ @Override public void sampleOperation2() { //写相关的代码 } }
对象适配器模式:
从上图能够看出,Adaptee类并无sampleOperation2()方法,而客户端则期待这个方法。为使客户端可以使用Adaptee类,须要提供一个包装(Wrapper)类Adapter。这个包装类包装了一个Adaptee的实例,从而此包装类可以把Adaptee的API与Target类的API衔接起来。Adapter与Adaptee是委派关系,这决定了适配器模式是对象的。
示例代码:
public interface Target { /** * 这是源类Adaptee也有的方法 */ public void sampleOperation1(); /** * 这是源类Adapteee没有的方法 */ public void sampleOperation2(); } public class Adaptee { public void sampleOperation1(){} }
适配器类:
public class Adapter { private Adaptee adaptee; public Adapter(Adaptee adaptee){ this.adaptee = adaptee; } /** * 源类Adaptee有方法sampleOperation1 * 所以适配器类直接委派便可 */ public void sampleOperation1(){ this.adaptee.sampleOperation1(); } /** * 源类Adaptee没有方法sampleOperation2 * 所以由适配器类须要补充此方法 */ public void sampleOperation2(){ //写相关的代码 } }
类适配器和对象适配器的权衡
对于类适配器因为适配器直接继承了Adaptee,使得适配器不能和Adaptee的子类一块儿工做,由于继承是静态的关系,当适配器继承了Adaptee后,就不可能再去处理 Adaptee的子类了。
对于对象适配器一个适配器能够把多种不一样的源适配到同一个目标。换言之,同一个适配器能够把源类和它的子类都适配到目标接口。由于对象适配器采用的是对象组合的关系,只要对象类型正确,是否是子类都无所谓。
对于类适配器适配器能够重定义Adaptee的部分行为,至关于子类覆盖父类的部分实现方法。
对于对象适配器要重定义Adaptee的行为比较困难,这种状况下,须要定义Adaptee的子类来实现重定义,而后让适配器组合子类。虽然重定义Adaptee的行为比较困难,可是想要增长一些新的行为则方便的很,并且新增长的行为可同时适用于全部的源。
对于类适配器,仅仅引入了一个对象,并不须要额外的引用来间接获得Adaptee。
对于对象适配器,须要额外的引用来间接获得Adaptee。
建议尽可能使用对象适配器的实现方式,多用合成或聚合、少用继承。固然,具体问题具体分析,根据须要来选用实现方式,最适合的才是最好的。
适配器模式的优势
更好的复用性:系统须要使用现有的类,而此类的接口不符合系统的须要。那么经过适配器模式就可让这些功能获得更好的复用。
更好的扩展性:在实现适配器功能的时候,能够调用本身开发的功能,从而天然地扩展系统的功能。
适配器模式的缺点
过多的使用适配器,会让系统很是零乱,不易总体进行把握。好比,明明看到调用的是A接口,其实内部被适配成了B接口的实现,一个系统若是太多出现这种状况,无异于一场灾难。所以若是不是颇有必要,能够不使用适配器,而是直接对系统进行重构。
基本概念:为其余对象提供一种代理以控制对这个对象的访问。也能够说,在出发点到目的地之间有一道中间层,意为代理。
为何要使用
受权机制不一样级别的用户对同一对象拥有不一样的访问权利,如在论坛系统中,就使用Proxy进行受权机制控制,访问论坛有两种人:注册用户和游客(未注册用户),论坛就经过相似ForumProxy这样的代理来控制这两种用户对论坛的访问权限。
某个客户端不能直接操做到某个对象,但又必须和那个对象有所互动。
举例两个具体状况:
总之原则是,对于开销很大的对象,只有在使用它时才建立,这个原则能够为咱们节省不少宝贵的Java内存。因此,有些人认为Java耗费资源内存,我觉得这和程序编制思路也有必定的关系。
如何使用??
以论坛系统为例,访问论坛系统的用户有多种类型:注册普通用户、论坛管理者、系统管理者、游客。注册普通用户才能发言,论坛管理者能够管理他被受权的论坛,系统管理者能够管理全部事务等,这些权限划分和管理是使用Proxy完成的。
在Forum中陈列了有关论坛操做的主要行为,如论坛名称,论坛描述的获取和修改,帖子发表删除编辑等,在ForumPermissions中定义了各类级别权限的用户:
public class ForumPermissions implements Cacheable { /** * Permission to read object. */ public static final int READ = 0; /** * Permission to administer the entire sytem. */ public static final int SYSTEM_ADMIN = 1; /** * Permission to administer a particular forum. */ public static final int FORUM_ADMIN = 2; /** * Permission to administer a particular user. */ public static final int USER_ADMIN = 3; /** * Permission to administer a particular group. */ public static final int GROUP_ADMIN = 4; /** * Permission to moderate threads. */ public static final int MODERATE_THREADS = 5; /** * Permission to create a new thread. */ public static final int CREATE_THREAD = 6; /** * Permission to create a new message. */ public static final int CREATE_MESSAGE = 7; /** * Permission to moderate messages. */ public static final int MODERATE_MESSAGES = 8; public boolean isSystemOrForumAdmin() { return (values[FORUM_ADMIN] || values[SYSTEM_ADMIN]); } //相关操做代码 }
所以,Forum中各类操做权限是和ForumPermissions定义的用户级别有关系的,做为接口Forum的实现:ForumProxy正是将这种对应关系联系起来。好比,修改Forum的名称,只有论坛管理者或系统管理者能够修改,代码以下:
public class ForumProxy implements Forum { private ForumPermissions permissions; private Forum forum; this.authorization = authorization; public ForumProxy(Forum forum, Authorization authorization,ForumPermissions permissions){ this.forum = forum; this.authorization = authorization; this.permissions = permissions; } ..... public void setName(String name) throws UnauthorizedException, ForumAlreadyExistsException{ //只有是系统或论坛管理者才能够修更名称 if (permissions.isSystemOrForumAdmin()) { forum.setName(name); } else { throw new UnauthorizedException(); } } ... }
而DbForum才是接口Forum的真正实现,以修改论坛名称为例:
public class DbForum implements Forum, Cacheable { ... public void setName(String name) throws ForumAlreadyExistsException { .... this.name = name; //这里真正将新名称保存到数据库中 saveToDb(); .... } ... }
凡是涉及到对论坛名称修改这一事件,其余程序都首先得和ForumProxy打交道,由ForumProxy决定是否有权限作某同样事情,ForumProxy是个名副其实的"网关","安全代理系统"。
在平时应用中,无可避免总要涉及到系统的受权或安全体系,无论你有无心识的使用Proxy,实际你已经在使用Proxy了。
流程图
基本概念:装饰模式(Decorator),动态地给一个对象添加一些额外的职责,就增长功能来讲,装饰模式比生成子类更为灵活。
UML结构图:
上图是Decorator 模式的结构图,让咱们能够进行更方便的描述:
Component
是定义一个对象接口,能够给这些对象动态地添加职责。
ConcreteComponent
是定义了一个具体的对象,也能够给这个对象添加一些职责。
Decorator是装饰抽象类,继承了Component,从外类来扩展Component类的功能,但对于Component来讲,是无需知道Decorator存在的。ConcreteDecorator就是具体的装饰对象,起到给Component添加职责的功能。
如何使用??
假设情景:某人装扮本身形象,穿衣服,裤子,鞋子,戴帽子等来把本身给包装起来,须要把所需的功能按正确的顺序串联起来进行控制,咱们应该如何设计才能作到呢?以下,先看下代码结构图:
先建立一个接口类:Component.java
public interface Component { void show(); }
建立一个具体的 ConcreteComponent 来实现 Component 接口:Person.java
public class Person implements Component{ private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } public Person(String name){ this.name = name; } @Override public void show() { System.out.println("装扮的" + name); } }
建立装饰类 Decorator 实现 Component 接口
public class Decorator implements Component{ private Component mComponent; public void decoratorObj(Component component){ mComponent = component; } @Override public void show() { if(mComponent != null){ mComponent.show(); } } }
分别建立具体的装饰类:Jeans.java , Pelisse.java, Sandal.java ...等等,分别继承 Decorator.java 类
/** 牛仔裤 */ public class Jeans extends Decorator { @Override public void show(){ System.out.println("穿牛仔裤"); super.show(); } }
客户端测试类
/** * 装饰模式测试客户端 */ public class DecoratorClient { public static void main(String[] args) { System.out.println("Welcome to Andy.Chen Blog!" +"\n" +"Decorator Patterns." +"\n"); Person mPerson = new Person("Andy"); Sandal mSandal = new Sandal(); Jeans mJeans = new Jeans(); TShirt mShirt = new TShirt(); mShirt.decoratorObj(mPerson); mJeans.decoratorObj(mShirt); mSandal.decoratorObj(mJeans); mSandal.show(); } }
测试结果
Welcome to Andy.Chen Blog! Decorator Patterns. 穿凉鞋 穿牛仔裤 穿T-Shirt 装扮的Andy
总结
Decorator
模式有如下的优缺点:
比静态继承更灵活与对象的静态继承相比,Decorator模式提供了更加灵活的向对象添加职责的方式,可使用添加和分离的方法,用装饰在运行时刻增长和删除职责。使用继承机制增长职责须要建立一个新的子类,若是须要为原来全部的子类都添加功能的话,每一个子类都须要重写,增长系统的复杂度,此外能够为一个特定的Component类提供多个Decorator,这种混合匹配是适用继承很难作到的。
Decorator 与它的Component不同Decorator是一个透明的包装,若是咱们从对象标识的观点出发,一个被装饰了的组件与这个组件是有差异的,所以使用装饰时不该该以来对象标识。
产生许多小对象,采用Decorator模式进行系统设计每每会产生许多看上去相似的小对象,这些对象仅仅在他们相互链接的方式上有所不一样。
1,http://www.cnblogs.com/forlina/archive/2011/06/21/2086114.html
2,http://www.cnblogs.com/java-my-life/archive/2012/04/13/2442795.html
3,http://blog.csdn.net/cjjky/article/details/7478788
4,http://blog.csdn.net/cjjky/article/details/7384951
5,http://blog.csdn.net/cjjky/article/details/7327200
6,https://www.cnblogs.com/pony1223/p/7608955.html