深入浅出设计模式学习笔记:三

装饰者模式:动态的将责任附加到对象上

Java I/O API也是使用此模式的

装饰模式的类图如下:

抽象组件(Component):抽象类,也可以是接口,规范了动态接收责任的对象。

具体组件(Concrete Component):定义一个将要接收附加责任的类,该组件可以单独使用,或者是被装饰者包装起来使用。

抽象装饰组件(Decorator):抽象类,也可以是接口,拥有一个构件(Component)对象的实例,并定义一个与抽象构件接口一致的接口。

具体装饰组件(Concrete ComponentA,Concrete ComponentB):负责装饰具体的组件,给具体的组件添加责任,装饰者中有一个实例变量,可以记录被装饰者;装饰者可以扩展Component的状态,也可以加上新的方法,新行为是通过在旧行为前面或者后面做一些计算来添加的。

举例说明:小明想开一个饮品店,需要制定饮品的分类以及价格,饮品的主要原料是水,其他的原料我们称之为调料,包括牛奶,白砂糖,咖啡粉,红茶,水果等等,加的调料不一样,饮品的价格也不一样,各种材料的价格如下:

原料 价格(元)
1
牛奶 2
咖啡粉 2
红茶 1
绿茶 1
蔓越莓 2
柠檬 2
白砂糖 1

具体类图如下:

具体的代码如下所示:

  1 //抽象类,相当于类图中的抽象组件,所有的被装饰者都继承该类,并实现其中的抽象方法
  2 abstract class Drink{
  3     String description = "Unknow Drink";
  4     //定义获取描述的方法,返回变量description
  5     public String getDescription(){
  6         return description;
  7         }
  8     //抽象方法,所有继承该抽象类的之类都需实现该方法
  9     public abstract int cost();
 10 }
 11 //具体实现类,相当于类图中的具体组件,一般认为是被装饰者
 12 class Water extends Drink{
 13    public Water(){
 14        description = "水";
 15    }
 16     @Override
 17     public int cost() {
 18         return 1;
 19     }
 20 }
 21
 22 //抽象装饰组件
 23 abstract class Condiment extends Drink{
 24     Drink drink;
 25     public Condiment(Drink drink){
 26         this.drink = drink;
 27     }
 28     public abstract String getDescription();
 29 }
 30 /**
 31  * 具体装饰组件:需要让装饰者能够持有被装饰者,做法如下:
 32  * 1:定义一个被装饰者的实例变量
 33  * 2:想办法让被装饰者记录在实例变量中,这里的做法是通过构造函数实现
 34  * @author SAMSUNG
 35  *
 36  */
 37 class RedTea extends Condiment{
 38     public RedTea(Drink tmpDrink){
 39         super(tmpDrink);
 40     }
 41     //获取完整的描述,除了自己的描述外,还通过委托,得到被装饰者的描述,两者结合得到完整的描述
 42     @Override
 43     public String getDescription() {
 44         return drink.getDescription()+" 加红茶";
 45     }
 46     @Override
 47     public int cost() {
 48         return 2 + drink.cost();
 49     }
 50 }
 51 //具体装饰组件
 52 class Sugar extends Condiment{
 53     public Sugar(Drink tmpDrink){
 54         super(tmpDrink);
 55     }
 56     @Override
 57     public String getDescription() {
 58
 59         return drink.getDescription()+" 加白砂糖";
 60     }
 61     @Override
 62     public int cost() {
 63         return 1 + drink.cost() ;
 64     }
 65 }
 66
 67 //具体装饰组件
 68 class Lemon extends Condiment{
 69   public Lemon(Drink tmpDrink){
 70       super(tmpDrink);
 71   }
 72     @Override
 73     public String getDescription() {
 74
 75         return drink.getDescription()+" 加柠檬";
 76     }
 77     @Override
 78     public int cost() {
 79         return 1 + drink.cost() ;
 80     }
 81 }
 82
 83
 84 //测试类
 85 public class DrinkTest {
 86
 87     public static void main(String[] args) {
 88
 89         Drink drink1 = new Water();
 90         //打印不添加任何装饰者的被装饰者的信息
 91         System.out.println(drink1.getDescription()+" 价钱:"+drink1.cost());
 92         //使用redtea装饰
 93         drink1 = new RedTea(drink1);
 94         System.out.println(drink1.getDescription()+" 价钱:"+drink1.cost());
 95         //使用sugar装饰
 96         drink1 = new Sugar(drink1);
 97         System.out.println(drink1.getDescription()+" 价钱:"+drink1.cost());
 98         //使用lemon装饰
 99         drink1 = new Lemon(drink1);
100         System.out.println(drink1.getDescription()+" 价钱:"+drink1.cost());
101     }
102 }

运行结果如下:

代码分析:

1、抽象类都可以换成接口,接口是一种极度抽象的类型,比抽象类更加抽象;

2、装饰抽象类(Condiment )持有一个被装饰者抽象类(Drink)的引用,通过构造函数,传入Drink的一个对象作为参数,并将该参数赋给引用,使得装饰者可以持有被装饰者;

3、所有具体的装饰者的构造函数都调用了super(tmpDrink)方法,具体实现依赖抽象,体现了依赖倒置原则,当有新的装饰者加入的时候,不需要修改代码,只需定义一个新的装类,并让该类继承装饰者抽象类,就可以成为一个新的具体装饰者,体现了对扩展开放,对修改关闭的设计原则;

4、由运行结果可知: 多个装饰者可以包装一个装饰者,叫做装饰者链;

5、装饰者(Condiment )与被装饰者(Water)具有相同的类型,这里虽然使用了继承,使用继承的的目的在于达到“类型匹配",而不是获得”行为“;如果依赖于继承,那么类的行为只能在编译时静态决定,反之,利用组合,可在运行时利用装饰者增加新的行为。

装饰者模式的优缺点:

优点:

1、可以给对象添加很多额外的行为,扩展对象的行为,比继承更具有灵活性;

2、通过不同的装饰类,或者多个装饰类的排列组合,在运行时改变对象的行为,使得对象具有更强大的功能;

缺点:

1、会产生很多的小对象,多度使用的话增加了系统的复杂性;

2、虽然比继承具有很高的灵活性,但是也意味着出错的可能性越高,排错比较麻烦。

时间: 2024-08-08 14:40:11

深入浅出设计模式学习笔记:三的相关文章

深入浅出设计模式学习笔记:一

设计模式 1.定义:是一套被反复使用.多数人知晓的.经过分类编目的.代码设计经验的总结 2.优点:代码复用,易于维护,易于理解性,保证代码的可靠性 3.分类:设计模式分为3种类型,共23种模式 创建型模式,共五种:工厂方法模式.抽象工厂模式.单例模式.建造者模式.原型模式. 结构型模式,共七种:适配器模式.装饰器模式.代理模式.外观模式.桥接模式.组合模式.享元模式. 行为型模式,共十一种:策略模式.模板方法模式.观察者模式.迭代子模式.责任链模式.命令模式.备忘录模式.状态模式.访问者模式.中

java/android 设计模式学习笔记(14)---外观模式

这篇博客来介绍外观模式(Facade Pattern),外观模式也称为门面模式,它在开发过程中运用频率非常高,尤其是第三方 SDK 基本很大概率都会使用外观模式.通过一个外观类使得整个子系统只有一个统一的高层的接口,这样能够降低用户的使用成本,也对用户屏蔽了很多实现细节.当然,在我们的开发过程中,外观模式也是我们封装 API 的常用手段,例如网络模块.ImageLoader 模块等.其实我们在开发过程中可能已经使用过很多次外观模式,只是没有从理论层面去了解它. 转载请注明出处:http://bl

设计模式学习笔记(目录篇)

设计模式学习笔记(目录篇) 为了方便查看,特此将设计模式学习笔记系列单独做一个目录. 1   设计模式学习笔记(一:命令模式) 2   设计模式学习笔记(二:观察者模式) 3   设计模式学习笔记(三:装饰模式) 4   设计模式学习笔记(四:策略模式) 5   设计模式学习笔记(五:适配器模式) 6   设计模式学习笔记(六:责任链模式) 7   设计模式学习笔记(七:外观模式) 8   设计模式学习笔记(八:迭代器模式) 9   设计模式学习笔记(九:中介者模式) 10  设计模式学习笔记(

java/android 设计模式学习笔记(12)---组合模式

这篇我们来介绍一下组合模式(Composite Pattern),它也称为部分整体模式(Part-Whole Pattern),结构型模式之一.组合模式比较简单,它将一组相似的对象看作一个对象处理,并根据一个树状结构来组合对象,然后提供一个统一的方法去访问相应的对象,以此忽略掉对象与对象集合之间的差别.这个最典型的例子就是数据结构中的树了,如果一个节点有子节点,那么它就是枝干节点,如果没有子节点,那么它就是叶子节点,那么怎么把枝干节点和叶子节点统一当作一种对象处理呢?这就需要用到组合模式了. 转

java/android 设计模式学习笔记(9)---代理模式

这篇博客我们来介绍一下代理模式(Proxy Pattern),代理模式也成为委托模式,是一个非常重要的设计模式,不少设计模式也都会有代理模式的影子.代理在我们日常生活中也很常见,比如上网时连接的代理服务器地址,更比如我们平时租房子,将找房子的过程代理给中介等等,都是代理模式在日常生活中的使用例子. 代理模式中的代理对象能够连接任何事物:一个网络连接,一个占用很多内存的大对象,一个文件,或者是一些复制起来代价很高甚至根本不可能复制的一些资源.总之,代理是一个由客户端调用去访问幕后真正服务的包装对象

java/android 设计模式学习笔记(6)---适配器模式

这篇来介绍一下适配器模式(Adapter Pattern),适配器模式在开发中使用的频率也是很高的,像 ListView 和 RecyclerView 的 Adapter 等都是使用的适配器模式.在我们的实际生活中也有很多类似于适配器的例子,比如香港的插座和大陆的插座就是两种格式的,为了能够成功适配,一般会在中间加上一个电源适配器,形如: 这样就能够将原来不符合的现有系统和目标系统通过适配器成功连接. 说到底,适配器模式是将原来不兼容的两个类融合在一起,它有点类似于粘合剂,将不同的东西通过一种转

java/android 设计模式学习笔记(3)---工厂方法模式

这篇来介绍一下工厂方法模式(Factory Method Pattern),在实际开发过程中我们都习惯于直接使用 new 关键字用来创建一个对象,可是有时候对象的创造需要一系列的步骤:你可能需要计算或取得对象的初始设置:选择生成哪个子对象实例:或在生成你需要的对象之前必须先生成一些辅助功能的对象,这个时候就需要了解该对象创建的细节,也就是说使用的地方与该对象的实现耦合在了一起,不利于扩展,为了解决这个问题就需要用到我们的工厂方法模式,它适合那些创建复杂的对象的场景,工厂方法模式也是一个使用频率很

java/android 设计模式学习笔记(2)---观察者模式

这篇来讲一下观察者模式,观察者模式在实际项目中使用的也是非常频繁的,它最常用的地方是GUI系统.订阅--发布系统等.因为这个模式的一个重要作用就是解耦,使得它们之间的依赖性更小,甚至做到毫无依赖.以GUI系统来说,应用的UI具有易变性,尤其是前期随着业务的改变或者产品的需求修改,应用界面也经常性变化,但是业务逻辑基本变化不大,此时,GUI系统需要一套机制来应对这种情况,使得UI层与具体的业务逻辑解耦,观察者模式此时就派上用场了. PS:对技术感兴趣的同鞋加群544645972一起交流. 设计模式

java/android 设计模式学习笔记(5)---对象池模式

这次要介绍一下对象池模式(Object Pool Pattern),这个模式为常见 23 种设计模式之外的设计模式,介绍的初衷主要是在平时的 android 开发中经常会看到,比如 ThreadPool 和 MessagePool 等. 在 java 中,所有对象的内存由虚拟机管理,所以在某些情况下,需要频繁创建一些生命周期很短使用完之后就可以立即销毁,但是数量很大的对象集合,那么此时 GC 的次数必然会增加,这时候为了减小系统 GC 的压力,对象池模式就很适用了.对象池模式也是创建型模式之一,