装饰者模式
装饰者模式的概念
在不必改变原类文件和使用继承的情况下,动态地扩展一个对象的功能。它是通过创建一个包装对象,也就是装饰来包裹真实的对象。
装饰对象接受所有来自客户端的请求。它把这些请求转发给真实的对象。装饰对象可以在转发这些请求以前或以后增加一些附加功能。
这样就确保了在运行时,不用修改给定对象的结构就可以在外部增加附加的功能。在面向对象的设计中,通常是通过继承来实现对给定类的功能扩展。
应用场景
比如我们去买一个肉夹馍,你可以选择加生菜、鸡蛋、鸡柳、香肠等等,一个肉夹馍加上不同的配料价格是不同的,那么我们如何去计算价钱呢?
可能我们首先会想到使用继承!
首先定义一个原始的肉夹馍基类接口,对于添加生菜、鸡柳、香肠这些配料分别写一个实现类,然后对这些配料的组合又分别写一个基类,那这里我们就需要添加多达十几种新类来完成我们的功能了。这种方式肯定是不合理的,那么我们就可以使用装饰者模式来设计我们的程序了。
类UML图
(1)抽象组件(Component)角色:给出一个抽象类,以规范准备接收附加功能的对象。
(2)具体组件(Concrete Component)角色:定义一个将要接收附加功能的类。
(3)装饰(Decorator)角色:持有一个组件(Component)对象的实例,并实现一个与抽象构件接口一致的接口。
(4)具体装饰(Concrete Decorator)角色:负责给组件对象添加上附加的功能。
肉夹馍实例
抽象组件(Component)角色:首先我们是定义一个抽象类Bread,同时定义好基础的功能:
/** * @Author: BaiDing * @Date: 2018/6/19 14:26 * @Email: liujiabaiding@foxmail.com */ public abstract class Bread { /** * 得到手抓饼的配料 * @return */ public abstract String getDesc(); /** * 得到手抓饼价格 * @return */ public abstract int getPrice(); }
具体组件(Concrete Component)角色:定义一个被装饰的类,继承Bread抽象类,并实现具体功能:
/** * @Author: BaiDing * @Date: 2018/6/19 15:16 * @Email: liujiabaiding@foxmail.com */ public class ShreddedBread extends Bread { /** * 得到手抓饼的描述 * @return */ public String getDesc(){ return "手抓饼"; } /** * 得到手抓饼价格 * @return */ public int getPrice(){ return 5; } }
装饰(Decorator)角色:定义一个装饰抽象类DeractorBread,继承Bread抽象类,并拥有一个Bread实例:
/** * @Author: BaiDing * @Date: 2018/6/19 15:35 * @Email: liujiabaiding@foxmail.com */ public abstract class DeractorBread extends Bread { private Bread bread; DeractorBread(Bread bread){ this.bread = bread; } /** * 得到手抓饼的描述 * @return */ public String getDesc(){ return bread.getDesc(); } /** * 得到手抓饼价格 * @return */ public int getPrice(){ return bread.getPrice(); } }
具体装饰(Concrete Decorator)角色:定义具体装饰类,继承装饰抽象类DeractorBread,并在其中扩展具体组件角色的功能:
/** * @Author: BaiDing * @Date: 2018/6/19 15:42 * @Email: liujiabaiding@foxmail.com */ public class EggshrededBread extends DeractorBread { EggshrededBread(Bread bread) { super(bread); } @Override public String getDesc() { return "鸡蛋"+super.getDesc(); } @Override public int getPrice() { return 2+super.getPrice(); } }
/** * @Author: BaiDing * @Date: 2018/6/19 15:56 * @Email: liujiabaiding@foxmail.com */ public class SausageShreddedBread extends DeractorBread { SausageShreddedBread(Bread bread) { super(bread); } @Override public String getDesc() { return "香肠"+super.getDesc(); } @Override public int getPrice() { return 3+super.getPrice(); } }
现在我们可以测试一下 这个装饰者模式设计的代码有没有作用:
/** * @Author: BaiDing * @Date: 2018/6/19 15:45 * @Email: liujiabaiding@foxmail.com */ public class Test { public static void main(String[] args){ ShreddedBread shreddedCake=new ShreddedBread(); System.out.println(shreddedCake.getDesc()+" 价格:"+shreddedCake.getPrice()); // 手抓饼 价格:5 EggshrededBread eggshrededCake =new EggshrededBread(shreddedCake); System.out.println(eggshrededCake.getDesc()+" 价格:"+eggshrededCake.getPrice()); // 鸡蛋手抓饼 价格:7 SausageShreddedBread sausageShreddedCake =new SausageShreddedBread(shreddedCake); System.out.println(sausageShreddedCake.getDesc()+" 价格:"+sausageShreddedCake.getPrice()); // 香肠手抓饼 价格:8 SausageShreddedBread doubleCake =new SausageShreddedBread(eggshrededCake); System.out.println(doubleCake.getDesc()+" 价格:"+doubleCake.getPrice()); // 香肠鸡蛋手抓饼 价格:10 } }
加密实例
对一个明文密码进行加密是我们的项目肯定要有的功能,我们可以针对这一功能采用装饰者模式进行设计。比如对不同的密码需要采用不同的加密方式:
抽象组件(Component)角色:
/** * @Author: BaiDing * @Date: 2018/6/19 16:52 * @Email: liujiabaiding@foxmail.com */ public abstract class Cipher { /** * 加密接口 * @param text * @return */ public abstract String encrypt(String text); }
具体组件(Concrete Component)角色:
/** * @Author: BaiDing * @Date: 2018/6/19 16:53 * @Email: liujiabaiding@foxmail.com */ public class SimpleCipher extends Cipher { /** * 简单密文加密实现 * @param text * @return */ @Override public String encrypt(String text) { StringBuilder str= new StringBuilder(); for(int i=0;i<text.length();i++) { char c=text.charAt(i); if(c>='a'&&c<='z') { c+=6; if(c>'z') c-=26; if(c<'a') c+=26; } if(c>='A'&&c<='Z') { c+=6; if(c>'Z') c-=26; if(c<'A') c+=26; } str.append(c); } return str.toString(); } }
装饰(Decorator)角色:
/** * @Author: BaiDing * @Date: 2018/6/19 16:55 * @Email: liujiabaiding@foxmail.com */ public abstract class CipherDecorator extends Cipher { private Cipher cipher; CipherDecorator(Cipher cipher){ this.cipher = cipher; } @Override public String encrypt(String text) { return cipher.encrypt(text); } }
具体装饰(Concrete Decorator)角色:
/** * @Author: BaiDing * @Date: 2018/6/19 16:56 * @Email: liujiabaiding@foxmail.com */ public class ComplexCipher extends CipherDecorator { public ComplexCipher(Cipher cipher) { super(cipher); } @Override public String encrypt(String text) { String result=super.encrypt(text); result= this.reverse(result); return result; } /** * 将密文反转 * @param text * @return */ private String reverse(String text) { StringBuilder str= new StringBuilder(); for(int i=text.length();i>0;i--) { str.append(text.substring(i - 1, i)); } return str.toString(); } }
/** * @Author: BaiDing * @Date: 2018/6/19 17:00 * @Email: liujiabaiding@foxmail.com */ public class AdvancedCipher extends CipherDecorator { public AdvancedCipher(Cipher cipher) { super(cipher); } @Override public String encrypt(String text) { String result=super.encrypt(text); result=mod(result); return result; } private String mod(String text) { StringBuilder str= new StringBuilder(); for(int i=0;i<text.length();i++) { String c=String.valueOf(text.charAt(i)%6); str.append(c); } return str.toString(); } }
最终测试结果:
/** * @Author: BaiDing * @Date: 2018/6/19 17:02 * @Email: liujiabaiding@foxmail.com */ public class Test { public static void main(String[] args){ String password = "jiawensishi110"; String result ; SimpleCipher simpleCipher = new SimpleCipher(); result = simpleCipher.encrypt(password); System.out.println(result); // pogcktyoyno110 ComplexCipher complexCipher =new ComplexCipher(simpleCipher); result = complexCipher.encrypt(password); System.out.println(result); // 011onyoytkcgop AdvancedCipher advancedCipher=new AdvancedCipher(complexCipher); result = advancedCipher.encrypt(password); System.out.println(result); // 01132131253134 } }