Java 的设计模式之一装饰者模式
刚开始接触装饰者的设计模式,感觉挺难理解的,不够后来花了一个晚上的时间,终于有头绪了
装饰者设计模式:如果想对已经存在的对象进行装饰,那么就定义一个类,在类中对已经有的对象进行功能的增强或添加另外的行为,这个类就叫装饰者类。被修饰的类叫被装饰者类,是已经存在有的功能。在装饰者类之间又可以互相装饰
特点:
1.装饰类通过构造方法来接收被装饰者的对象,调用它里面的功能或行为
2. 基于对被装饰对象的功能进行扩展,提供更强大的功能
Java中的IO流是典型的装饰者模式
下面来看一行简短的代码:
扩展一个接口,定义一个抽象的方法,这个接口实际上就是一个被装饰者类
interface Work {
public void work();
}
画画类:
class Drawing implements Work { //实现接口
@Override
public void work() { //必须实现接口中的方法
// TODO Auto-generated method stub
System.out.println("画画");
}
}
上色类:
class Colour implements Work {
Work w;//在内部维护一个被装饰的类
public Colour(Work w) {
this.w = w;
}
@Override
public void work() {
w.work();
System.out.println("给画上色");
}
}
装裱类:
class Mounting implements Work {
Work w;//在内部维护一个被装饰的类
public Mounting(Work w) {
this.w = w;
}
@Override
public void work() {
w.work();
System.out.println("给画装裱");
}
}
测试类:
public class Test {
public static void main(String[] args) throws FileNotFoundException {
Work w = new Drawing();
Colour c = new Colour(w);
Mounting m = new Mounting(c);
m.work();
}
}
上面是一个简单的装饰者模式。
装饰者模式的设计原则:
1.多用组合,少用继承
继承的子类实现父类的行为,是在编译时静态决定的,而且继承的行为是相同的,但是利用装饰者之间的相互修饰(组合)
就可以扩展出强大的功能,可以动态的进行扩展,也可以撤销
2.对扩展开放,对修改关闭
扩展是在继承的前提下实现,在子类中修改。扩展是在继承被装饰者类实现行为或功能,不需要修改装饰者的类,只是在此基础 上,装饰另外的功能或行为
需求:定义一个人吃面,可以加生菜,也可以加辣椒,也可以都加
EatNoodle类:
class EatNoodle {
public void eat() {
System.out.print("吃面");
}
}
装饰者类
class SunEatNoodle1 {
EatNoodle eatNd;
public SunEatNoodle1(EatNoodle eatNd) { //定义构造方法来接收被装饰者的对象
this.eatNd = eatNd;
}
public void eat() {
eatNd.eat();
System.out.println("加点香菜,感觉好吃");
}
}
装饰者之间的相互修饰
class SunEatNoodle2 {
//EatNoodle eatNd;
SunEatNoodle1 sunEat1;
public SunEatNoodle2( SunEatNoodle1 sunEat1) { //定义构造方法来接收装饰者的对象
//this.eatNd = eatNd;
this.sunEat1 = sunEat1;
}
public void eat() {
System.out.println();
//eatNd.eat();
sunEat1.eat();
System.out.println("再来点辣椒,就更好吃了");
}
}
测试类:
public class Demo1 {
public static void main(String[] args) {
EatNoodle eatNoodle = new EatNoodle();
//eatNoodle.eat();
SunEatNoodle1 sunEat1 = new SunEatNoodle1(eatNoodle);
sunEat1.eat();
SunEatNoodle2 sunEat2 = new SunEatNoodle2(sunEat1);//装饰者类之间的相互修饰
sunEat2.eat();
}
}
运行结果:

装饰者与继承的关系
在添加 不同功能的时候。我们会想到了用继承来实现。而且刚学装饰者模式的时候,觉得挺难理解的,装饰者的前世今生就是继承。那为什么不用继承呢?这样岂不是更容易理解,用起来也挺方便。下面通过一个简单的Demo做一下比较。
需求:用继承来实现通过readLine读取代码 ,每一行加上一个行号和分号的功能
//1.添加行号,默认继承BufferedReader
class BufferedReaderLineNum extends BufferedReader { int count = 0; public BufferedReaderLineNum(BufferedReader in) { //Reader:默认创建一个目标文件的缓冲字符输入流的大小
super(in);
} @Override//3.重写父类的readLine方法
public String readLine() throws IOException { String countent = super.readLine();//调用父类默认的行号 if (countent == null) {
return null;
} //System.out.println(count + " " + countent);
count++;
return count + " " + countent;
}
} //添加分号
class BufferedReaderSemicolon extends BufferedReader {
BufferedReader reader; public BufferedReaderSemicolon(BufferedReader in) {//Reader:默认创建一个目标文件的缓冲字符输入流的大小
super(in);
this.reader = in;
} @Override//3.重写父类的readLine方法
public String readLine() throws IOException { String countent = reader.readLine();
if (countent == null) { //判断数据已经读完
return null;
} return countent + ";";
}
} public class Demo1 { public static void main(String[] args) throws IOException { //FileReader用于字符输入流,FileInputStream是用字节输入流
//1.创建通道,拿到一个指定的目标文件
FileReader fileRead = new FileReader("C:\\java\\decorator\\Test.java");
BufferedReader reader = new BufferedReader(fileRead); //2.创建行号的缓冲流
BufferedReaderLineNum readerLineNum = new BufferedReaderLineNum(reader); //.创建分号的缓冲流
BufferedReaderSemicolon readerSemicolon = new BufferedReaderSemicolon(readerLineNum); String content = null;
//使用readLine(),包含该行内容的字符串,不包含任何行终止符,如果已到达流末尾,则返回 null
while((content = readerSemicolon.readLine()) != null) {
System.out.println(content);
}
//4.关闭资源
readerLineNum.close();
}
}
然后再通过装饰者模式来实现上面的功能:
//添加行号
class BufferederReadLineNum extends BufferedReader { BufferedReader bufferedReader; //1.内部维护的被装饰者的类
int count = 1; public BufferederReadLineNum(BufferedReader read) {
super(read);//如果没有这行代码,会显示编译报错,显示没有隐式性的给这个构造函数定义
this.bufferedReader = read;
} @Override
public String readLine() throws IOException { String countent = bufferedReader.readLine(); if(countent == null) {
return null;
} countent = count + " " + countent;
count++;
return countent;
}
} //2.添加分号
class BufferedReaderSemicolon1 extends BufferedReader { BufferedReader bufferedReader; //1.内部维护的被装饰者的类 public BufferedReaderSemicolon1(BufferedReader read) {
super(read);
this.bufferedReader = read;
} @Override//3.重写父类的readLine方法
public String readLine() throws IOException { String countent = super.readLine(); //调用父类默认的行号
if (countent == null) { //判断数据已经读完
return null;
} return countent + ";";
}
} public class Test2 { public static void main(String[] args) throws IOException { //1.创建通道,拿到一个指定的目标文件
FileReader fileRead = new FileReader("C:\\java\\代码\\src\\Test.java"); //2.创建缓冲区
BufferedReader bufferedReader = new BufferedReader(fileRead); //3创建分号的缓冲流
BufferedReaderSemicolon1 readerSemicolon = new BufferedReaderSemicolon1(bufferedReader); //创建行号的缓冲流 在装饰者创建的
BufferederReadLineNum readerLineNum = new BufferederReadLineNum(readerSemicolon); //4.读取数据
String content = null;
//使用readLine(),包含该行内容的字符串,不包含任何行终止符,如果已到达流末尾,则返回 null
while((content = readerLineNum.readLine()) != null) {
System.out.println(content);
}
//5.关闭资源
readerLineNum.close(); }
}
通过上面的代码,可能不能完全看出使用装饰者模式的强大功能,你可以在多创建几个类,添加多个功能,结果就显而易见了。
在实现多个功能的时候,使用继承的体系会过于庞大,显得很臃肿。
使用了装饰者来进行动态性的添加一些附加功能,确保在运行时,不用改变该对象的结构就可以在外部添加附加的功能。通常也是通过继承来实现给定类的功能扩展来实现更强大的功能。提高了代码的可维护性和简洁性。
Java 的设计模式之一装饰者模式的更多相关文章
- JAVA基础——设计模式之装饰者模式
装饰模式 : 对新房进行装修并没有改变房屋的本质,但它可以让房子变得更漂亮.更温馨.更实用. 在软件设计中,对已有对象(新房)的功能进行扩展(装修). 把通用功能封装在装饰器中,用到的地方 ...
- Java 设计模式泛谈&装饰者模式和单例模式
设计模式(Design Pattern) 1.是一套被反复使用.多人知晓的,经过分类编目 的 代码设计经验总结.使用设计模式是为了可重用代码,让代码更容易维护以及扩展. 2.简单的讲:所谓模式就是得到 ...
- Java设计模式 - - 单例模式 装饰者模式
Java设计模式 单例模式 装饰者模式 作者 : Stanley 罗昊 [转载请注明出处和署名,谢谢!] 静态代理模式:https://www.cnblogs.com/StanleyBlogs/p/1 ...
- Java设计模式之装饰器模式
1.装饰器模式的定义(保持接口,扩展功能) Decorate装饰器,顾名思义,就是动态的给一个对象添加一些额外的职责,就好比对房子进行装修一样. 2.装饰器模式的特征 具有一个装饰对象. 必须拥有与被 ...
- 设计模式之装饰者模式-java实例
设计模式之装饰者模式 需求场景 我们有了别人提供的产品,但是别人提供的产品对我们来说还不够完善,我们需要对这个产品的功能进行补强,此时可以考虑使用装饰者模式. 我们已经有了产品,而且这个产品的功能非常 ...
- Java IO流以及装饰器模式在其上的运用
流概述 Java中,流是一种有序的字节序列,可以有任意的长度.从应用流向目的地称为输出流,从目的地流向应用称为输入流. Java的流族谱 Java的 java.io 包中囊括了整个流的家族,输出流和输 ...
- [转载]Java中继承、装饰者模式和代理模式的区别
[转载]Java中继承.装饰者模式和代理模式的区别 这是我在学Java Web时穿插学习Java设计模式的笔记 我就不转载原文了,直接指路好了: 装饰者模式和继承的区别: https://blog.c ...
- 实践GoF的23种设计模式:装饰者模式
摘要:装饰者模式通过组合的方式,提供了能够动态地给对象/模块扩展新功能的能力.理论上,只要没有限制,它可以一直把功能叠加下去,具有很高的灵活性. 本文分享自华为云社区<[Go实现]实践GoF的2 ...
- C#设计模式(9)——装饰者模式(Decorator Pattern)
一.引言 在软件开发中,我们经常想要对一类对象添加不同的功能,例如要给手机添加贴膜,手机挂件,手机外壳等,如果此时利用继承来实现的话,就需要定义无数的类,如StickerPhone(贴膜是手机类).A ...
随机推荐
- 字典树+博弈 CF 455B A Lot of Games(接龙游戏)
题目链接 题意: A和B轮流在建造一个字,每次添加一个字符,要求是给定的n个串的某一个的前缀,不能添加字符的人输掉游戏,输掉的人先手下一轮的游戏.问A先手,经过k轮游戏,最后胜利的人是谁. 思路: 很 ...
- [转]webpack
什么是 webpack? webpack是近期最火的一款模块加载器兼打包工具,它能把各种资源,例如JS(含JSX).coffee.样式(含less/sass).图片等都作为模块来使用和处理. 我们可以 ...
- java的基础知识文件操作和标识符
1.文件夹的操作 dir :显示当前文件夹中的所有文件和文件夹. cd 路径: 进入到指定的路径. cd .. : 回到上一级目录 cd \ : 回到当前目录的跟目录 md 文件夹名 创建一个 ...
- jquery简单插件写法
(function($){ /** * 遮罩插件 * 使用:$('#id').qloading(options); * 详见:/plugins/_11_qloading/qloading.html * ...
- zookeeper在linux下自启动
Linux下设置zookeeper开机自启动 一.以root用户登录系统: 二.进入init.d文件夹 cd /etc/init.d/ 三.创建并打开zookeeper文件 vi zookeeper ...
- 基于注解的Spring AOP入门、增强Advice实例
这篇文章简单通过一个例子,介绍几种增强的基本配置,以方便spring框架初学者对aop的代码结构有个清楚的了解认识.首先,spring支持aop编程,支持aspectJ的语法格式来表示切入点,切面,增 ...
- redhat6 yum源配置
第一次接触redhat系统,安装软件时,发现没有ubuntu的apt-get包管理器,自带的yum包管理器又什么都找不到,网上搜了好久,终于把yum配置好了,感谢博主们- 使用redhat系统自带的y ...
- System.Dynamic.ExpandoObject 类型的简单使用
该类型可以实现的是动态添加属性和移除属性,有点类似 js 中对象的操作,非常灵活 static void Main(string[] args) { dynamic obj = new System. ...
- 一、javascript中的类
1.找出对象的构造器----constructor/instanceof constructor是用模版实例化对象的时候附带的一个额外属性,这个属性指向创建该对象时所使用的javascript构造函数 ...
- 一鼓作气 博客--第五篇 note5
一.迭代器 二.装饰器 三.生成器 1.生成列表的方式有几种 2.把列表每个数都加1 2.1 data =[1,2,3] for i in map(lambda x:x+1,data):print(i ...