博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
装饰器模式
阅读量:6546 次
发布时间:2019-06-24

本文共 4991 字,大约阅读时间需要 16 分钟。

hot3.png

我们都知道,可以使用两种方式给一个类或者对象添加行为。

        一是使用继承。继承是给一个类添加行为的比较有效的途径。通过使用继承,可以使得子类在拥有自身方法的同时,还可以拥有父类的方法。但是使用继承是静态的,在编译的时候就已经决定了子类的行为,我们不便于控制增加行为的方式和时机。

        二是使用关联。组合即将一个对象嵌入到另一个对象中,由另一个对象来决定是否引用该对象来扩展自己的行为。这是一种动态的方式,我们可以在应用程序中动态的控制。

        与继承相比,关联关系的优势就在于不会破坏类的封装性,且具有较好的松耦合性,可以使系统更加容易维护。但是它的缺点就在于要创建比继承更多的对象。

        一、基本定义                                                                                                                     

        装饰者模式,动态地将责任附加到对象上。若要扩展功能,装饰者提供了比继承更加有弹性的替代方案。

        二、模式结构                                                                                                                     

        装饰者模式UML结构图。

        Component: 抽象构件。是定义一个对象接口,可以给这些对象动态地添加职责。

        ConcreteComponent:具体构件。是定义了一个具体的对象,也可以给这个对象添加一些职责。

        Decorator: 抽象装饰类。是装饰抽象类,继承了Component,从外类来扩展Component类的功能,但对于Component来说,是无需知道Decorator存在的。

        ConcreteDecorator:具体装饰类,起到给Component添加职责的功能。

 

        三、实现装饰者模式                                                                                                                                           

        情景模式:星巴兹以扩张速度快而闻名。在里面购买咖啡时,可以要求在其中加入各种调料,星巴兹会根据所加入的调料收取不同的费用,也就是说不同的咖啡与调料之间有N多不同的组合方式。每种咖啡和调料都有不同的收费。如果这个时候我们使用继承方式,则会陷入无以复加的地步。这里会有N多个类,出现“类爆炸”现象。

        结构图如下:

        装饰者模式提供了一个比较好的解决方案。

        编码实现:

        Component  Beverage.java

[java] 

  1. public abstract class Beverage {  

  2.     protected String description = "Unknown Beverage";  

  3.   

  4.     public String getDescription() {  

  5.         return description;  

  6.     }  

  7.   

  8.     public abstract double cost();  

  9. }  

        四个组件:HouseBlend.java

[java] 

  1. public class HouseBlend extends Beverage {  

  2.   

  3.     public HouseBlend(){  

  4.         description = "HouseBlend";  

  5.     }  

  6.       

  7.     @Override  

  8.     public double cost() {  

  9.         return 0.89;  

  10.     }  

  11.   

  12. }  

        DarkRoast.java

[java] 

  1. public class DarkRoast extends Beverage {  

  2.     public DarkRoast(){  

  3.         description = "DarkRoast";  

  4.     }  

  5.     @Override  

  6.     public double cost() {  

  7.         return 1.05;  

  8.     }  

  9.   

  10. }  

        Espresso.java

[java] 

  1. public class DarkRoast extends Beverage {  

  2.     public DarkRoast(){  

  3.         description = "DarkRoast";  

  4.     }  

  5.     @Override  

  6.     public double cost() {  

  7.         return 1.05;  

  8.     }  

  9.   

  10. }  

        Decat.java

[java] 

  1. public Decat(){  

  2.     description = "Decat";  

  3. }  

  4.       

  5. @Override  

  6. public double cost() {  

  7.     return 0.99;  

  8. }  

        CondimentDecorator.java

[java] 

  1. public abstract class CondimentDecorator extends Beverage{  

  2.     public abstract String getDescription();  

  3. }  

        Milk.java

[java] 

  1. public class Milk extends CondimentDecorator {  

  2.     Beverage beverage;  

  3.       

  4.     public Milk(Beverage beverage){  

  5.         this.beverage = beverage;  

  6.     }  

  7.       

  8.     @Override  

  9.     public String getDescription() {  

  10.         return beverage.getDescription() + " , Milk";  

  11.     }  

  12.   

  13.     @Override  

  14.     public double cost() {  

  15.         return beverage.cost() + 0.3;  

  16.     }  

  17. }  

        Mocha.java

[java] 

  1. public class Mocha extends CondimentDecorator {  

  2.     Beverage beverage;  

  3.     public Mocha(Beverage beverage){  

  4.         this.beverage = beverage;  

  5.     }  

  6.       

  7.     @Override  

  8.     public String getDescription() {  

  9.         return beverage.getDescription() + " , Mocha";  

  10.     }  

  11.   

  12.     @Override  

  13.     public double cost() {  

  14.         return beverage.cost() + 0.20;  

  15.     }  

  16.   

  17. }  

        Soy.java

[java] 

  1. public class Soy extends CondimentDecorator{  

  2.     Beverage beverage;  

  3.     public Soy(Beverage beverage) {  

  4.         this.beverage = beverage;  

  5.     }  

  6.     @Override  

  7.     public String getDescription() {  

  8.         return beverage.getDescription() + " , Soy";  

  9.     }  

  10.   

  11.     @Override  

  12.     public double cost() {  

  13.         return beverage.cost() + 0.10;  

  14.     }  

  15.   

  16. }  

        Whip.java

[java] 

  1. public class Whip extends CondimentDecorator {  

  2.     Beverage beverage;  

  3.     public Whip(Beverage beverage){  

  4.         this.beverage = beverage;  

  5.     }  

  6.     @Override  

  7.     public String getDescription() {  

  8.         return beverage.getDescription() + " , Whip";  

  9.     }  

  10.   

  11.     @Override  

  12.     public double cost() {  

  13.         return beverage.cost() + 0.20;  

  14.     }  

  15.   

  16. }  

        测试程序

[java] 

  1. public class StarbuzzCoffee {  

  2.   

  3.     /** 

  4.      * @param args 

  5.      */  

  6.     public static void main(String[] args) {  

  7.         Beverage beverage = new Espresso();  

  8.         System.out.println(beverage.getDescription() + " $" + beverage.cost());  

  9.           

  10.         Beverage beverage2 = new DarkRoast();  

  11.         beverage2 = new Mocha(beverage2);  

  12.         beverage2 = new Mocha(beverage2);  

  13.         beverage2 = new Whip(beverage2);  

  14.         System.out.println(beverage2.getDescription() + " $" + beverage2.cost());     

  15.     }  

  16.   

  17. }  

        运行结果

        四、装饰者模式的优缺点                                                                                                   

        优点

           1、装饰者模式可以提供比继承更多的灵活性

           2、可以通过一种动态的方式来扩展一个对象的功能,在运行时选择不同的装饰器,从而实现不同的行为。

           3、通过使用不同的具体装饰类以及这些装饰类的排列组合,可以创造出很多不同行为的组合。可以使用多个具体装饰类来装饰同一对象,得到功能更为强大的对象。

           4、具体构件类与具体装饰类可以独立变化,用户可以根据需要增加新的具体构件类和具体装饰类,在使用时再对其进行组合,原有代码无须改变,符合“开闭原则”。

 

        缺点

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

           2、这种比继承更加灵活机动的特性,也同时意味着装饰模式比继承更加易于出错,排错也很困难,对于多次装饰的对象,调试时寻找错误可能需要逐级排查,较为烦琐。

 

        、装饰者模式的适用场景                                                                                              

                 1、在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责。

                 2、需要动态地给一个对象增加功能,这些功能也可以动态地被撤销。  当不能采用继承的方式对系统进行扩充或者采用继承不利于系统扩展和维护时。

        六、总结                                                                                                                          

                 1、 组合和委托可以在运行时动态的添加新的行为,而继承是静态的,在系统编译时就已经决定了对象的行为。

                 2、装饰者模式意味着一群装饰者类,这些类用来包装具体组件

                 3、装饰者可以在被装饰者的行为前面或者后面加上自己的行为,甚至可以将被装饰者的行为整个取代掉,从而达到特定的目的。

                 4、可以用多个装饰者包装一个组件。

                 5、装饰者一般对于组件的客户是透明的,除非客户程序依赖于组件的具体类型。

                 6、装饰者会导致设计中出现许多的小对象,如果过度的使用,会让系统变得更加复杂。

                 7、装饰者和被装饰者对象有相同的超类型。

图如下:

Source类是被装饰类,Decorator类是一个装饰类,可以为Source类动态的添加一些功能,代码如下:

[java] 

  1. public interface Sourceable {  

  2.     public void method();  

  3. }  

[java] 

  1. public class Source implements Sourceable {  

  2.   

  3.     @Override  

  4.     public void method() {  

  5.         System.out.println("the original method!");  

  6.     }  

  7. }  

[java] 

  1. public class Decorator implements Sourceable {  

  2.   

  3.     private Sourceable source;  

  4.       

  5.     public Decorator(Sourceable source){  

  6.         super();  

  7.         this.source = source;  

  8.     }  

  9.     @Override  

  10.     public void method() {  

  11.         System.out.println("before decorator!");  

  12.         source.method();  

  13.         System.out.println("after decorator!");  

  14.     }  

  15. }  

测试类:

[java] 

  1. public class DecoratorTest {  

  2.   

  3.     public static void main(String[] args) {  

  4.         Sourceable source = new Source();  

  5.         Sourceable obj = new Decorator(source);  

  6.         obj.method();  

  7.     }  

  8. }  

输出:

before decorator!

the original method!
after decorator!

装饰器模式的应用场景:

1、需要扩展一个类的功能。

2、动态的为一个对象增加功能,而且还能动态撤销。(继承不能做到这一点,继承的功能是静态的,不能动态增删。)

缺点:产生过多相似的对象,不易排错!

转载于:https://my.oschina.net/u/1792865/blog/399426

你可能感兴趣的文章
[LeetCode]Longest Increasing Path in a Matrix
查看>>
C++基础之适配器
查看>>
集合set-深入学习
查看>>
C#语言学习——面向对象的几大原则
查看>>
zk 常用资料整理(转)
查看>>
JavaScript 字符串操作
查看>>
Android中asset文件夹和raw文件夹区别
查看>>
Fuel 30 分钟快速安装openstack 分类: 软件插件学习 ...
查看>>
第二章家庭作业 2.78
查看>>
[Python] SQLBuilder 演示样例代码
查看>>
Android 下拉刷新上拉载入 多种应用场景 超级大放送(上)
查看>>
<转>cookie和session的区别
查看>>
Risc-V指令集
查看>>
Python进阶04 函数的参数对应
查看>>
【分布计算环境学习笔记】4 Enterprise Java Bean
查看>>
C语言结构体的“继承”
查看>>
c++ const修饰符 总结
查看>>
Cocos2d-x--Box2D绘制出两个矩形框的解决方案
查看>>
配置Tomcat的JVM的大小解决Tomcat内存溢出的问题
查看>>
centos 编译安装PHP5.4
查看>>