1.什么是装饰者模式

动态给对象增加功能,从一个对象的外部来给对象添加功能,相当于改变了对象的外观,比用继承的方式更加的灵活。当使用装饰后,从外部系统的角度看,就不再是原来的那个对象了,而是使用一系列的装饰器装饰过后的对象。

2.结构

    角色:
    Component:组件对象的抽象接口,可以给这些对象动态的增加职责/功能。
    ConcreteComponent:具体的组件的对象,实现组件对象的接口,是被装饰器装饰的原始对象,即可以给这个对象动态的添加职责。
    Decorator:所有装饰器的抽象父类,实现了组件对象的接口,并且持有一个组件对象(被装饰的对象)。
    ConcreteDecorator:具体的装饰器,具体实现向装饰对象添加功能。

3.示例

   下面我们用装饰者模式实现如下的功能:
    要求用户输入一段文字,比如 Hello Me,然后屏幕输出几个选项
    1 :加密
    2 :反转字符串
    3:转成大写

    4:转成小写
    5:扩展或者剪裁到10个字符,不足部分用!补充
    6:用户输入 任意组合,比如 1,3 表示先执行1的逻辑,再执行3的逻辑
    根据用户输入的选择,进行处理后,输出结果

//组件对象的接口
public interface ICompoment { String display(String str);
}
//具体的组件对象
public class DetailCompoment implements ICompoment {
@Override
public String display(String str) {
System.out.println("原来内容:"+str);
return str;
}
}
//所有装饰器的父类,实现了组件接口
public abstract class Decorator implements ICompoment{
//持有了一个组件对象
protected ICompoment compoment; public Decorator(ICompoment compoment) {
this.compoment = compoment;
} @Override
public String display(String str) {
return compoment.display(str);
}
//对组件对象进行装饰的抽象方法
public abstract String transform(String str);
}
//加密、解密工具类
public class EnDecodeUtil { private static final char password='a'; public static String encodeDecode(String str){
char[] chars = str.toCharArray();
for (int i = 0; i < chars.length; i++) {
chars[i] = (char) (chars[i] ^ password);
}
return new String(chars);
}
}
//加密装饰器
public class EncodeDecorator extends Decorator { public EncodeDecorator(ICompoment compoment) {
super(compoment);
} @Override
public String display(String str) {
String display = super.display(str);
return transform(display);
} @Override
public String transform(String str) {
System.out.println("invoke EncodeDecorator....");
return EnDecodeUtil.encodeDecode(str);
}
}
//解密装饰器
public class DecodeDecorator extends Decorator { public DecodeDecorator(ICompoment compoment) {
super(compoment);
} @Override
public String display(String str) {
String display = super.display(str);
return transform(display);
} @Override
public String transform(String str) {
System.out.println("invoke DecodeDecorator...");
return EnDecodeUtil.encodeDecode(str);
}
}
//反转 装饰器
public class ReverseDecorator extends Decorator { public ReverseDecorator(ICompoment compoment) {
super(compoment);
} @Override
public String display(String str) {
String display = super.display(str);
String transform = transform(display);
return transform;
} @Override
public String transform(String str) {
System.out.println("invoke ReverseDecorator....");
StringBuilder sb = new StringBuilder(str);
return sb.reverse().toString();
} }
//转为大写的装饰器
public class UpperDecorator extends Decorator {
public UpperDecorator(ICompoment compoment) {
super(compoment);
} @Override
public String display(String str) {
String display = super.display(str);
String transform = transform(display);
return transform;
} @Override
public String transform(String str) {
System.out.println("invoke UpperDecorator....");
return str.toUpperCase();
}
}
//转为小写的装饰器
public class LowerDecorator extends Decorator{
public LowerDecorator(ICompoment compoment) {
super(compoment);
} @Override
public String display(String str) {
String display = super.display(str);
String transform = transform(display);
return transform;
} @Override
public String transform(String str) {
System.out.println("invoke lowerDecorator....");
return str.toLowerCase();
}
}
//裁剪、扩充装饰器
public class ExtendOrSplitDecorator extends Decorator {
public ExtendOrSplitDecorator(ICompoment compoment) {
super(compoment);
} @Override
public String display(String str) {
String display = super.display(str);
String transform = transform(display);
return transform;
} @Override
public String transform(String str) {
System.out.println("invoke ExtendOrSplitDecorator....");
if (str != null) {
if (str.length() > 10) {
return str.substring(0,10);
}else{
int repeatCount = 10 -str.length();
StringBuilder sb = new StringBuilder(str);
for (int i = 0; i < repeatCount; i++) {
sb.append("!");
}
return sb.toString();
}
}
return null;
}
}
//测试代码
public static void main(String[] args) {
//将输入内容转为大写,再反转
ReverseDecorator reverseDecorator = new ReverseDecorator(new UpperDecorator(new DetailCompoment()));
String display = reverseDecorator.display("wo shi zhongguo ren.");
System.out.println(display); //将输入内容转为小写,在裁剪或者扩展
ExtendOrSplitDecorator decorator = new ExtendOrSplitDecorator(new LowerDecorator(new DetailCompoment()));
String display1 = decorator.display("I Love");
System.out.println(display1); //将输入内容转为小写,再反转,然后加密
EncodeDecorator decorator1 = new EncodeDecorator(new ReverseDecorator(new LowerDecorator(new DetailCompoment())));
String display2 = decorator1.display("顶级机密:1941年12月 日本偷袭珍珠港! 银行密码是:1234ADC");
System.out.println(display2);
System.out.println("++++++++++");
//将输入内容先反转、再转为小写,然后加密
EncodeDecorator decorator2 = new EncodeDecorator(new LowerDecorator(new ReverseDecorator(new DetailCompoment())));
String display3 = decorator2.display("顶级机密:1941年12月 日本偷袭珍珠港! 银行密码是:1234ADC");
System.out.println(display3); System.out.println("============");
//对上面的加密内容,进行解密
DecodeDecorator decodeDecorator = new DecodeDecorator(decorator1);
String display4 = decodeDecorator.display("顶级机密:1941年12月 日本偷袭珍珠港! 银行密码是:1234ADC");
System.out.println(display4);
}

控制台输出:

原来内容:wo shi zhongguo ren.
invoke UpperDecorator....
invoke ReverseDecorator....
.NER OUGGNOHZ IHS OW
原来内容:I Love
invoke lowerDecorator....
invoke ExtendOrSplitDecorator....
i love!!!!
原来内容:顶级机密:1941年12月 日本偷袭珍珠港! 银行密码是:1234ADC
invoke lowerDecorator....
invoke ReverseDecorator....
invoke EncodeDecorator....
URSP[晎硠宧蠭钗A⦆湎玁玬裌倖杍斄A杩SP帕PUXPサ宧杛细頗
++++++++++
原来内容:顶级机密:1941年12月 日本偷袭珍珠港! 银行密码是:1234ADC
invoke ReverseDecorator....
invoke lowerDecorator....
invoke EncodeDecorator....
URSP[晎硠宧蠭钗A⦆湎玁玬裌倖杍斄A杩SP帕PUXPサ宧杛细頗
============
原来内容:顶级机密:1941年12月 日本偷袭珍珠港! 银行密码是:1234ADC
invoke lowerDecorator....
invoke ReverseDecorator....
invoke EncodeDecorator....
invoke DecodeDecorator...
cda4321:是码密行银 !港珠珍袭偷本日 月21年1491:密机级顶

4.装饰者模式在jdk中的应用I/O

    InputStream 相当于装饰者模式的Component
    FileInputStream,ByteArrayInputStream,ObjectInputStream这些对象直接继承了InputStream,相当于装饰者模式中的ConcreteComponent
    FilterInputStream 继承了InputStream,并且持有了一个InputStream ,相当于装饰者模式中的Decorator
    BufferedInputStream,PushbackInputStream,LineNumberInputStream,DataInputStream继承了FilterInputStream,相当于装饰者模式中的ConcreteDecorator
 //这里FileInputStream 相当于组件对象,BufferedInputStream这个装饰器装饰了FileInputStream对象
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(new File("fileName")));
byte[] buff = new byte[1024];
bis.read(buff);
System.out.println(new String(buff));

5.优点、缺点,使用场合

  优点:
    1.比继承更灵活
    从为对象添加功能的角度来看,装饰者模式比继承更为灵活。继承是静态的,一旦继承,所有的子类都有一样的功能。装饰者模式采用把功能分离到每个装饰器当中,
   通过对象组合的方式,在运行时动态的组合功能,被装饰对象最终由哪些功能,是由运行时动态组合的功能决定的。
    2.复用功能更容易
    装饰模式把一系列复杂的功能分散到每个装饰器中,一般情况下每个装饰器只实现一个功能,使得实现装饰器变得简单,有利于装饰器功能的复用,可以给一个对象添加
    多个装饰器,也可以把一个装饰器装饰多个对象,从而实现复用装饰器的功能。
    3.简化高层定义
    装饰者模式可以通过组合装饰器的方式,为对象添加任意多的功能;因此在高层定义的时候,不必把所有的功能都定义处理,只需要定义最基本的就可以了,在需要的时候可以
    通过组合装饰器的方式来完成所需的功能。   缺点:会产生较多的细粒度的对象
  装饰模式把一系列复杂的功能分散到每个装饰器中,一般情况下每个装饰器只实现一个功能,这样会产生很多细粒度的对象,并且功能越复杂,细粒度对象越多。 本质:动态组合
注意:装饰者模式只是改变组件对象的外观Facde,并没有改变其内核   使用场合:
    如果需要再不影响其他对象的情况下,以动态、透明的方式给对象增加职责,可以使用装饰者模式。
    如果不适合使用子类进行扩展的时候,可以考虑使用装饰者模式。装饰者模式使用的是对象组合的方式。 不适合子类扩展:比如扩展功能需要的子类太多,造成子类数量呈爆炸性增长。

装饰者模式 Decoration的更多相关文章

  1. 修饰者模式(装饰者模式,Decoration)

    1. 装饰者模式,动态地将责任附加到对象上.若要扩展功能,装饰者提供了比继承更加有弹性的替代方案. 2.组合和继承的区别 继承.继承是给一个类添加行为的比较有效的途径.通过使用继承,可以使得子类在拥有 ...

  2. 修饰者模式(装饰者模式,Decoration)

    1. 装饰者模式,动态地将责任附加到对象上.若要扩展功能,装饰者提供了比继承更加有弹性的替代方案. 2.组合和继承的区别 继承.继承是给一个类添加行为的比较有效的途径.通过使用继承,可以使得子类在拥有 ...

  3. Java中设计模式之装饰者模式-3

    装饰者模式: 动态地将责任附加到对象上.若要扩展功能,装饰者提供了比继承更加有弹性的替代方案. 装饰者核心:实现功能组合 继承与组合区别: 继承 继承是给一个类添加行为的比较有效的途径.通过使用继承, ...

  4. Groovy 设计模式 -- 装饰器模式

    http://groovy-lang.org/design-patterns.html#_chain_of_responsibility_pattern 装饰器模式, 起到美化原始对象的作用. 一个被 ...

  5. JAVA装饰者模式(从现实生活角度理解代码原理)

    装饰者模式可以动态地给一个对象添加一些额外的职责.就增加功能来说,Decorator模式相比生成子类更为灵活. 该模式的适用环境为: (1)在不影响其他对象的情况下,以动态.透明的方式给单个对象添加职 ...

  6. 设计模式(三):“花瓶+鲜花”中的装饰者模式(Decorator Pattern)

    在前两篇博客中详细的介绍了"策略模式"和“观察者模式”,今天我们就通过花瓶与鲜花的例子来类比一下“装饰模式”(Decorator Pattern).在“装饰模式”中很好的提现了开放 ...

  7. 设计模式(九)装饰者模式(Decorator Pattern)

    一.引言 在软件开发中,我们经常想要对一类对象添加不同的功能,例如要给手机添加贴膜,手机挂件,手机外壳等,如果此时利用继承来实现的话,就需要定义无数的类,如StickerPhone(贴膜是手机类).A ...

  8. PHP 装饰器模式

    装饰器模式:是在不必改变原类文件和使用继承的情况下,动态地扩展一个对象的功能. [装饰器模式中主要角色] 抽象组件角色(Component):定义一个对象接口,以规范准备接受附加责任的对象,即可以给这 ...

  9. C#设计模式-装饰者模式

    在软件开发中,我们经常想要对一类对象添加不同的功能,例如要给手机添加贴膜,手机挂件,手机外壳等,如果此时利用继承来实现的话,就需要定义无数的类,如StickerPhone(贴膜是手机类).Access ...

随机推荐

  1. Hadoop 中利用 mapreduce 读写 mysql 数据

    Hadoop 中利用 mapreduce 读写 mysql 数据   有时候我们在项目中会遇到输入结果集很大,但是输出结果很小,比如一些 pv.uv 数据,然后为了实时查询的需求,或者一些 OLAP ...

  2. 移动站应该尝试百度MIP的五个原因

    MIP是什么?MIP是百度在2016年提出的移动网页加速器项目. MIP能做什么?MIP能帮助站长和网站开发者快速搭建移动端页面. MIP怎么加速?MIP从前端渲染和页面网络传输两方面进行优化,杜绝页 ...

  3. 04.LoT.UI 前后台通用框架分解系列之——轻巧的弹出框

    LOT.UI分解系列汇总:http://www.cnblogs.com/dunitian/p/4822808.html#lotui LoT.UI开源地址如下:https://github.com/du ...

  4. Android-armebi-v7a、arm64-v8a、armebi的坑

    先来一波扫盲: armeabi:针对普通的或旧的arm v5 cpu armeabi-v7a:针对有浮点运算或高级扩展功能的arm v7 cpu(32位ARM设备) arm64-v8a:64位ARM设 ...

  5. mysql 学习总结

    MYSQL的增.删.查.改   注册.授权 #创建一个对数据库中的表有一些操作权限的用户,其中OPERATION可以用all privileges替换,DBNAME.TABLENAME可以用*替换,表 ...

  6. iOS开发之多种Cell高度自适应实现方案的UI流畅度分析

    本篇博客的主题是关于UI操作流畅度优化的一篇博客,我们以TableView中填充多个根据内容自适应高度的Cell来作为本篇博客的使用场景.当然Cell高度的自适应网上的解决方案是铺天盖地呢,今天我们的 ...

  7. 实现一个类 RequireJS 的模块加载器 (二)

    2017 新年好 ! 新年第一天对我来说真是悲伤 ,早上兴冲冲地爬起来背着书包跑去实验室,结果今天大家都休息 .回宿舍的时候发现书包湿了,原来盒子装的牛奶盖子松了,泼了一书包,电脑风扇口和USB口都进 ...

  8. [数据结构]——二叉树(Binary Tree)、二叉搜索树(Binary Search Tree)及其衍生算法

    二叉树(Binary Tree)是最简单的树形数据结构,然而却十分精妙.其衍生出各种算法,以致于占据了数据结构的半壁江山.STL中大名顶顶的关联容器--集合(set).映射(map)便是使用二叉树实现 ...

  9. 流程表单中js如何清空SheetUser控件数据?

    昨天有人问我js怎么清空.我试了试,发现简单的赋给他空值,并没有用.只能给他赋一个真实存在的值才有用.于是跟踪了一下他的删除按钮. 效果如下 使用场景:可以根据字段的不同类别变更人员. js代码如下, ...

  10. 解决 Could not find com.android.tools.build:gradle 问题

    今天拉同事最新的代码,编译时老是报如下错误: Error:Could not find com.android.tools.build:gradle:2.2.0.Searched in the fol ...