装饰者模式 Decoration
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的更多相关文章
- 修饰者模式(装饰者模式,Decoration)
1. 装饰者模式,动态地将责任附加到对象上.若要扩展功能,装饰者提供了比继承更加有弹性的替代方案. 2.组合和继承的区别 继承.继承是给一个类添加行为的比较有效的途径.通过使用继承,可以使得子类在拥有 ...
- 修饰者模式(装饰者模式,Decoration)
1. 装饰者模式,动态地将责任附加到对象上.若要扩展功能,装饰者提供了比继承更加有弹性的替代方案. 2.组合和继承的区别 继承.继承是给一个类添加行为的比较有效的途径.通过使用继承,可以使得子类在拥有 ...
- Java中设计模式之装饰者模式-3
装饰者模式: 动态地将责任附加到对象上.若要扩展功能,装饰者提供了比继承更加有弹性的替代方案. 装饰者核心:实现功能组合 继承与组合区别: 继承 继承是给一个类添加行为的比较有效的途径.通过使用继承, ...
- Groovy 设计模式 -- 装饰器模式
http://groovy-lang.org/design-patterns.html#_chain_of_responsibility_pattern 装饰器模式, 起到美化原始对象的作用. 一个被 ...
- JAVA装饰者模式(从现实生活角度理解代码原理)
装饰者模式可以动态地给一个对象添加一些额外的职责.就增加功能来说,Decorator模式相比生成子类更为灵活. 该模式的适用环境为: (1)在不影响其他对象的情况下,以动态.透明的方式给单个对象添加职 ...
- 设计模式(三):“花瓶+鲜花”中的装饰者模式(Decorator Pattern)
在前两篇博客中详细的介绍了"策略模式"和“观察者模式”,今天我们就通过花瓶与鲜花的例子来类比一下“装饰模式”(Decorator Pattern).在“装饰模式”中很好的提现了开放 ...
- 设计模式(九)装饰者模式(Decorator Pattern)
一.引言 在软件开发中,我们经常想要对一类对象添加不同的功能,例如要给手机添加贴膜,手机挂件,手机外壳等,如果此时利用继承来实现的话,就需要定义无数的类,如StickerPhone(贴膜是手机类).A ...
- PHP 装饰器模式
装饰器模式:是在不必改变原类文件和使用继承的情况下,动态地扩展一个对象的功能. [装饰器模式中主要角色] 抽象组件角色(Component):定义一个对象接口,以规范准备接受附加责任的对象,即可以给这 ...
- C#设计模式-装饰者模式
在软件开发中,我们经常想要对一类对象添加不同的功能,例如要给手机添加贴膜,手机挂件,手机外壳等,如果此时利用继承来实现的话,就需要定义无数的类,如StickerPhone(贴膜是手机类).Access ...
随机推荐
- Hadoop 中利用 mapreduce 读写 mysql 数据
Hadoop 中利用 mapreduce 读写 mysql 数据 有时候我们在项目中会遇到输入结果集很大,但是输出结果很小,比如一些 pv.uv 数据,然后为了实时查询的需求,或者一些 OLAP ...
- 移动站应该尝试百度MIP的五个原因
MIP是什么?MIP是百度在2016年提出的移动网页加速器项目. MIP能做什么?MIP能帮助站长和网站开发者快速搭建移动端页面. MIP怎么加速?MIP从前端渲染和页面网络传输两方面进行优化,杜绝页 ...
- 04.LoT.UI 前后台通用框架分解系列之——轻巧的弹出框
LOT.UI分解系列汇总:http://www.cnblogs.com/dunitian/p/4822808.html#lotui LoT.UI开源地址如下:https://github.com/du ...
- Android-armebi-v7a、arm64-v8a、armebi的坑
先来一波扫盲: armeabi:针对普通的或旧的arm v5 cpu armeabi-v7a:针对有浮点运算或高级扩展功能的arm v7 cpu(32位ARM设备) arm64-v8a:64位ARM设 ...
- mysql 学习总结
MYSQL的增.删.查.改 注册.授权 #创建一个对数据库中的表有一些操作权限的用户,其中OPERATION可以用all privileges替换,DBNAME.TABLENAME可以用*替换,表 ...
- iOS开发之多种Cell高度自适应实现方案的UI流畅度分析
本篇博客的主题是关于UI操作流畅度优化的一篇博客,我们以TableView中填充多个根据内容自适应高度的Cell来作为本篇博客的使用场景.当然Cell高度的自适应网上的解决方案是铺天盖地呢,今天我们的 ...
- 实现一个类 RequireJS 的模块加载器 (二)
2017 新年好 ! 新年第一天对我来说真是悲伤 ,早上兴冲冲地爬起来背着书包跑去实验室,结果今天大家都休息 .回宿舍的时候发现书包湿了,原来盒子装的牛奶盖子松了,泼了一书包,电脑风扇口和USB口都进 ...
- [数据结构]——二叉树(Binary Tree)、二叉搜索树(Binary Search Tree)及其衍生算法
二叉树(Binary Tree)是最简单的树形数据结构,然而却十分精妙.其衍生出各种算法,以致于占据了数据结构的半壁江山.STL中大名顶顶的关联容器--集合(set).映射(map)便是使用二叉树实现 ...
- 流程表单中js如何清空SheetUser控件数据?
昨天有人问我js怎么清空.我试了试,发现简单的赋给他空值,并没有用.只能给他赋一个真实存在的值才有用.于是跟踪了一下他的删除按钮. 效果如下 使用场景:可以根据字段的不同类别变更人员. js代码如下, ...
- 解决 Could not find com.android.tools.build:gradle 问题
今天拉同事最新的代码,编译时老是报如下错误: Error:Could not find com.android.tools.build:gradle:2.2.0.Searched in the fol ...