1 概述

我们先来看一个快餐店的例子。

快餐店有炒面、炒饭这些快餐,可以额外附加鸡蛋、火腿、培根这些配菜,当然加配菜需要额外加钱,每个配菜的价钱通常不太一样,那么计算总价就会显得比较麻烦。

使用继承的方式存在的问题:

扩展性不好

如果要再加一种配料(火腿肠),我们就会发现需要给FriedRice和FriedNoodles分别定义一个子类。如果要新增一个快餐品类(炒河粉)的话,就需要定义更多的子类。

产生过多的子类

定义:

指在不改变现有对象结构的情况下,动态地给该对象增加一些职责(即增加其额外功能)的模式

2 结构

装饰(Decorator)模式中的角色:

  • 抽象构件(Component)角色 :定义一个抽象接口以规范准备接收附加责任的对象。
  • 具体构件(Concrete Component)角色 :实现抽象构件,通过装饰角色为其添加一些职责。
  • 抽象装饰(Decorator)角色 : 继承或实现抽象构件,并包含具体构件的实例,可以通过其子类扩展具体构件的功能。
  • 具体装饰(ConcreteDecorator)角色 :实现抽象装饰的相关方法,并给具体构件对象添加附加的责任。

3 案例

我们使用装饰者模式对快餐店案例进行改进,体会装饰者模式的精髓。

类图如下:

Ganish继承并聚合了FastFood

代码如下:

//快餐接口

//抽象构件
public abstract class FastFood {private float price;private String desc;
​public FastFood() {}
​public FastFood(float price, String desc) {this.price = price;this.desc = desc;}
​public void setPrice(float price) {this.price = price;}
​public float getPrice() {return price;}
​public String getDesc() {return desc;}
​public void setDesc(String desc) {this.desc = desc;}
​public abstract float cost();  //获取价格
}
​
//具体构件角色
//炒饭
public class FriedRice extends FastFood {​public FriedRice() {super(10, "炒饭");}
​public float cost() {return getPrice();}
}
​
//炒面(具体构件类)
public class FriedNoodles extends FastFood {​public FriedNoodles() {super(12, "炒面");}
​public float cost() {return getPrice();}
}
​
//抽象装饰者类角色
//配料类
public abstract class Garnish extends FastFood {​private FastFood fastFood;
​public FastFood getFastFood() {return fastFood;}
​public void setFastFood(FastFood fastFood) {this.fastFood = fastFood;}
​public Garnish(FastFood fastFood, float price, String desc) {super(price,desc);this.fastFood = fastFood;}
}
​
//鸡蛋配料
public class Egg extends Garnish {​public Egg(FastFood fastFood) {super(fastFood,1,"鸡蛋");}
​public float cost() {return getPrice() + getFastFood().getPrice();}
​@Overridepublic String getDesc() {return super.getDesc() + getFastFood().getDesc();}
}
​
//培根配料
public class Bacon extends Garnish {​public Bacon(FastFood fastFood) {​super(fastFood,2,"培根");}
​@Overridepublic float cost() {return getPrice() + getFastFood().getPrice();}
​@Overridepublic String getDesc() {return super.getDesc() + getFastFood().getDesc();}
}
​
//测试类
public class Client {public static void main(String[] args) {//点一份炒饭FastFood food = new FriedRice();//花费的价格System.out.println(food.getDesc() + " " + food.cost() + "元");
​System.out.println("========");//点一份加鸡蛋的炒饭FastFood food1 = new FriedRice();
​food1 = new Egg(food1);//花费的价格System.out.println(food1.getDesc() + " " + food1.cost() + "元");
​System.out.println("========");//点一份加培根的炒面FastFood food2 = new FriedNoodles();food2 = new Bacon(food2);//花费的价格System.out.println(food2.getDesc() + " " + food2.cost() + "元");}
}

好处:

饰者模式可以带来比继承更加灵活性的扩展功能,使用更加方便,可以通过组合不同的装饰者对象来获取具有不同行为状态的多样化的结果。装饰者模式比继承更具良好的扩展性,完美的遵循开闭原则,继承是静态的附加责任,装饰者则是动态的附加责任。
装饰类和被装饰类可以独立发展,不会相互耦合,装饰模式是继承的一个替代模式,装饰模式可以动态扩展一个实现类的功能。

4 使用场景

当不能采用继承的方式对系统进行扩充或者采用继承不利于系统扩展和维护时。

不能采用继承的情况主要有两类:

  • 第一类是系统中存在大量独立的扩展,为支持每一种组合将产生大量的子类,使得子类数目呈爆炸性增长;
  • 第二类是因为类定义不能继承(如final类)
    在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责。

当对象的功能要求可以动态地添加,也可以再动态地撤销时。

5 JDK源码解析

IO流中的包装类使用到了装饰者模式。BufferedInputStream,BufferedOutputStream,BufferedReader,BufferedWriter。

我们以BufferedWriter举例来说明,先看看如何使用BufferedWriter

public class Demo {public static void main(String[] args) throws Exception{//创建BufferedWriter对象//创建FileWriter对象FileWriter fw = new FileWriter("C:\\Users\\Think\\Desktop\\a.txt");BufferedWriter bw = new BufferedWriter(fw);
​//写数据bw.write("hello Buffered");
​bw.close();}
}

使用起来感觉确实像是装饰者模式,接下来看它们的结构:

小结:

BufferedWriter使用装饰者模式对Writer子实现类进行了增强,添加了缓冲区,提高了写数据的效率。

6 代理和装饰者的区别

静态代理和装饰者模式的区别:

相同点:

  • 都要实现与目标类相同的业务接口
  • 在两个类中都要声明目标对象
  • 都可以在不修改目标类的前提下增强目标方法

不同点:

  • 目的不同 装饰者是为了增强目标对象 静态代理是为了保护和隐藏目标对象
  • 获取目标对象构建的地方不同 装饰者是由外界传递进来,可以通过构造方法传递 静态代理是在代理类内部创建,以此来隐藏目标对象

Java设计模式-装饰者模式相关推荐

  1. Java设计模式——装饰者模式

    概述 本章可以称为"给爱用继承的人一个全新的设计眼界".我们即将再度探讨典型滥用问题.你将在本章学到如何使用对象组合的方式,做到在运行时装饰类.为什么呢?一旦你熟悉了装饰者的技巧, ...

  2. Java设计模式-装饰器模式 理论代码相结合

    继Java设计模式适配器模式后的装饰器模式来啦,让我们一起看看吧. 会了就当复习丫,不会来一起来看看吧. 很喜欢一句话:"八小时内谋生活,八小时外谋发展". 如果你也喜欢,让我们一 ...

  3. java设计模式装饰者模式优点_java设计模式之--装饰者模式

    装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其结构.这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装. 这种模式创建了一个装饰类,用来包装 ...

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

    Decorator装饰器,顾名思义,就是动态地给一个对象添加一些额外的职责,就好比为房子进行装修一样.因此,装饰器模式具有如下的特征: 它必须具有一个装饰的对象. 它必须拥有与被装饰对象相同的接口. ...

  5. java设计模式---装饰器模式

    装饰者模式 动态地将责任附加到对象上.若要扩展功能,装饰者提供了比继承更有弹性的替代方案. 具体被装饰者和抽象装饰类都继承于抽象被装饰者类,继承的是类型,而不是行为.行为来自装饰者和基础组件,或与其他 ...

  6. java装饰者模式服装搭配,学习、探究Java设计模式——装饰者模式

    定义 装饰者模式:在不改变原类文件以及不使用继承的情况下,动态地将责任附加到对象上,从而实现动态拓展一个对象的功能.它是通过创建一个包装对象,也就是装饰来包裹真实的对象. 设计原则 要使用装饰者模式, ...

  7. Java设计模式----------装饰器模式

    1.介绍 装饰器模式是一种结构型的设计模式.使用该模式的目的是为了较为灵活的对类进行扩展,而且不影响原来类的结构.有同学说可以通过继承的方式进行实现啊,没错,继承的确可以实现,但是继承的成本相对比较高 ...

  8. JAVA设计模式-装饰器模式(Decorator)

    装饰器模式(Decorator) 为了某个实现类在不修改原始类的基础上进行动态地覆盖或者增加方法 采用--------装饰器模式 实现类要保持与原有类的层级关系 装饰器模式是一种特殊的适配器模式 拿适 ...

  9. Java设计模式--装饰者模式【Decorator Pattern】

    有时,你想要在程序运行期间为某个对象组合新的行为,且在某种情况下,你需要对象的行为发生一些细小的变化,并且这些变化可以自由组合.这时,装饰者模式就可以满足这种需求. 所谓装饰者模式,也叫修饰者模式.装 ...

最新文章

  1. 2022-2028年中国免疫诊断行业市场前瞻与投资战略规划分析报告
  2. 转Redis性能测试
  3. 基于嵌入式linux 的车载定位系统设计,基于嵌入式Linux的GPS车载定位导航系统设计...
  4. 论文笔记(3)-Extracting and Composing Robust Features with Denoising Autoencoders
  5. linux(八)__yum工具
  6. java自定义异常报错
  7. 如何在SQL Server中分析存储子系统性能
  8. python和c混编_python与C、C++混编的四种方式(小结)
  9. 从何润东代言团宝,看团购行业逐渐成熟
  10. 如何快速的复习学习过的Python
  11. html 新浪微博分享申请,新浪微博API申请流程详解
  12. 安装office2010提示错误25541的解决方法
  13. 【ESP 保姆级教程】疯狂传感器篇 —— 案例:ESP8266 + BH1750 + webserver(局域网内查看曲线变化图)
  14. 计算机C语言好学吗?要是想自学应该怎么办?大学挂科赶紧恶补!
  15. 历史上的今天:大型计算机先驱和小型机之父诞生;中国雅虎邮箱成历史
  16. ios 历年wwdc
  17. 使用钢笔工具进行抠图
  18. html改变元素外边距,CSS 简明教程 - 外边距 ( margin ) 属性
  19. 战略决定结构是什么意思?
  20. 什么都是浮云 唯有云计算灿烂

热门文章

  1. 男生眼中“理想女友”工作排名,程序员排名第三,幼师倒数第一
  2. oSIP开发者手册 (二)
  3. Android图片加载之认识bitmap的四种加载方式
  4. 李迟2022年2月知识总结
  5. nodejs实践录:使用curl测试post请求
  6. 关于Ajax和@RequestBody配合使用的问题
  7. 【java】java ssh 远程执行命令 并且获取执行的结果
  8. 【Flink】Flink 写入 Clickhouse 大对象直接进入老年代 导致OOM
  9. 【kafka】支持超高并发的kafka网络设计
  10. 【Negix】Nginx 面试 一些题目