设计模式之装饰者模式

来源:互联网 发布:淘宝定做衣服 编辑:程序博客网 时间:2024/05/17 05:56

这几天。做项目中用到装饰者模式,然后仔细学了学。

本篇博客主要讲以下几个问题:

1.什么是装饰者模式

2.代码实现装饰者模式

3.装饰者模式优缺点

4.装饰者的使用场景

什么是装饰者模式

在不必改变原类文件和使用继承的情况下,动态地扩展一个对象的功能。它是通过创建一个包装对象,也就是装饰来包裹真实的对象。简单的说,
就是不改变原有类结构和功能的基础上,动态扩展类的功能

应用场景

咖啡店里咖啡中可以加不同的配料–摩卡、牛奶、糖、奶泡;不同的饮品加上不同的配料有不同的价钱,怎样实现呢?

可能你的第一印象会想到使用继承, 
1. 首先定义一个咖啡基类 
2. 对于加糖的,加牛奶的,加摩卡的 ,加奶泡的,分别写一个子类继承 
3. 对于加糖,又加奶的写一个类,对于对于加糖,又摩卡的写一个类,对于对于加糖、又奶泡的写一个类,对于加糖,又加奶、摩卡的写一个类—- 
说到这里,你会发现这里四种配料就要写十几种实现类了,那如果我们的配料是二十几种或者三十几种呢,那么使用继承这种 方式肯定会使我们的子类爆炸,那要怎样解决你,答案就是使用装饰者模式

注意:我觉得相比较继承,装饰者模式的一个优点是不同的功能之间可以迭代,也就是一个类可以随意选择拥有其他任意个扩展功能。

装饰者类UML图

代码实现

首先我们先来看一下我们的设计类图

  • 1) 首先我们定义一个Coffce基类
/** * @ explain:这里Coffee相当于我们的Component, * 是要装饰的类 * * @ author:xujun on 2016/7/10 23:16 * @ email:gdutxiaoxu@163.com */public abstract class Coffee {    /**     *     * @return 返回价格     */    public abstract int getPrice();    /**     * 返回名字     * @return     */    public abstract String getName();}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 2) 接着 我们定义一个Decorator类继承 我们的Coffice基类
/** * @ explain: * @ author:xujun on 2016/7/10 23:21 * @ email:gdutxiaoxu@163.com */public abstract class Decorator extends Coffee{    protected Coffee mCoffee;    /**     * 通过组合的方式把Coffee对象传递进来     * @param coffee     */    public Decorator(Coffee coffee){        mCoffee=coffee;    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 3)接下来我们来看我们的子类是怎样实现的
public class MilkDecorator extends Decorator {    /**     * 通过组合的方式把Coffee对象传递进来     *     * @param coffee     */    public MilkDecorator(Coffee coffee) {        super(coffee);    }    @Override    public int getPrice() {        return mCoffee.getPrice()+10;    }    @Override    public String getName() {        return "addMilk";    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

其实核心代码就下面一行,在原来的价格加上 加牛奶的价格

return mCoffee.getPrice()+10
  • 1
  • 1
  • 4)接下来不难想象加糖,就奶泡。就摩卡的操作,都是在原来的之上加上配料的价格
return mCoffee.getPrice()+2;return mCoffee.getPrice()+15;return mCoffee.getPrice()+20;
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3

总结

以后你想要计算加糖,就牛奶,加奶泡的咖啡的价格,只需要这样

mCoffee = new SimpleCoffee();mCoffee = new SugarDecorator(mCoffee);mCoffee = new MilkDecorator(mCoffee);mCoffee = new MilkFoamDecorator(mCoffee);int price1 = mCoffee.getPrice();System.out.println("price1="+price1);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

以后你想要计算加糖,就牛奶咖啡的价格,只需要这样

mCoffee = new SimpleCoffee();mCoffee = new SugarDecorator(mCoffee);mCoffee = new MilkDecorator(mCoffee);int price1 = mCoffee.getPrice();System.out.println("price1="+price1);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

一个追加功能的过程,一个额外功能就是一个小的装饰类,最后进行功能组合,很好的实现了代码的复用。

装饰者模式的优缺点

优点

  • 把类中的装饰功能从类中搬除,可以简化原来的类
  • 可以把类的 核心职责和装饰功能区分开来,结构清晰 明了并且可以去除相关类的重复的装饰逻辑。

装饰模式的特点

编辑
(1) 装饰对象和真实对象有相同的接口。这样客户端对象就能以和真实对象相同的方式和装饰对象交互。
(2) 装饰对象包含一个真实对象的引用(reference)
(3) 装饰对象接受所有来自客户端的请求。它把这些请求转发给真实的对象。
(4) 装饰对象可以在转发这些请求以前或以后增加一些附加功能。这样就确保了在运行时,不用修改给定对象的结构就可以在外部增加附加的功能。在面向对象的设计中,通常是通过继承来实现对给定类的功能扩展。

适用性

编辑
以下情况使用Decorator模式
1. 需要扩展一个类的功能,或给一个类添加附加职责。
2. 需要动态的给一个对象添加功能,这些功能可以再动态的撤销。
3. 需要增加由一些基本功能的排列组合而产生的非常大量的功能,从而使继承关系变的不现实。
4. 当不能采用生成子类的方法进行扩充时。一种情况是,可能有大量独立的扩展,为支持每一种组合将产生大量的子类,使得子类数目呈爆炸性增长。另一种情况可能是因为类定义被隐藏,或类定义不能用于生成子类。

优点

编辑
1. Decorator模式与继承关系的目的都是要扩展对象的功能,但是Decorator可以提供比继承更多的灵活性。
2. 通过使用不同的具体装饰类以及这些装饰类的排列组合,设计师可以创造出很多不同行为的组合。

缺点

编辑
1. 这种比继承更加灵活机动的特性,也同时意味着更加多的复杂性。
2. 装饰模式会导致设计中出现许多小类,如果过度使用,会使程序变得很复杂。
3. 装饰模式是针对抽象组件(Component)类型编程。但是,如果你要针对具体组件编程时,就应该重新思考你的应用架构,以及装饰者是否合适。当然也可以改变Component接口,增加新的公开的行为,实现“半透明”的装饰者模式。在实际项目中要做出最佳选择。

设计原则

编辑
1. 多用组合,少用继承。
利用继承设计子类的行为,是在编译时静态决定的,而且所有的子类都会继承到相同的行为。然而,如果能够利用组合的做法扩展对象的行为,就可以在运行时动态地进行扩展。
2. 开闭原则。类应设计的对扩展开放,对修改关闭。

参考:http://blog.csdn.net/lmj623565791/article/details/51854533



原创粉丝点击