zoukankan      html  css  js  c++  java
  • 浅谈设计模式--装饰者模式(Decorator Pattern)

    挖了设计模式这个坑,得继续填上。继续设计模式之路。这次讨论的模式,是

    装饰者模式(Decorator Pattern)

    装饰者模式,有时也叫包装者(Wrapper),主要用于静态或动态地为一个特定的对象增加新的特性,而不影响这个对象的类(allows behavior to be added to an individual object, either statically or dynamically, without affecting the behavior of other objects from the same class)。

    装饰者模式,主要用处是,灵活方便地增加特性到特定的对象上。请看下面的例子:

     1 /**
     2  * Coffee interface defines the functionality of Coffee implemented by decorator
     3  * @author YYC
     4  * 
     5  */
     6 public interface ICoffee {
     7 
     8     double getCost();
     9 
    10     String getIngredients();
    11 
    12 }
    13 
    14 
    15 /**
    16  * extension of a simple coffee without any extra ingredients
    17  * @author YYC
    18  *
    19  */
    20 public class SimpleCoffee implements ICoffee{
    21 
    22     public double getCost() {
    23         return 1;
    24     }
    25 
    26     public String getIngredients() {
    27         return "Coffee";
    28     }
    29 
    30 }
    31 
    32 
    33 /**
    34  * abstract decorator class - note that it implement Coffee interface
    35  * @author YYC
    36  * 
    37  */
    38 public abstract class CoffeDecorator implements ICoffee {
    39 
    40     protected final ICoffee decoratedCoffee;
    41     protected String ingredientSeparator = ",";
    42 
    43     public CoffeDecorator(ICoffee decoratedCoffee) {
    44         this.decoratedCoffee = decoratedCoffee;
    45     }
    46     
    47     public double getCost(){
    48         return decoratedCoffee.getCost();
    49     }
    50     
    51     public String getIngredients(){
    52         return decoratedCoffee.getIngredients();
    53     }
    54     
    55 }

    首先对于装饰者模式而已,一个公共的接口是必须的,在这里是ICoffee,代表咖啡的抽象接口。然后需要有一个简单的实现类以及一个装饰者的抽象类,作为具体装饰者的父类。接下来的是具体的装饰者类:

     1 /**
     2  * Decorator Milk that mixes milk with coffee
     3  * @author YYC
     4  *
     5  */
     6 public class Milk extends CoffeDecorator {
     7 
     8     public Milk(ICoffee decoratedCoffee) {
     9         super(decoratedCoffee);
    10     }
    11 
    12     public double getCost() {
    13         return super.getCost() + 0.5;
    14     }
    15 
    16     public String getIngredients() {
    17         return super.getIngredients() + ingredientSeparator + "Milk";
    18     }
    19 
    20 }
    21 
    22 
    23 /**
    24  * @author YYC 
    25  * Decorator Sprinkles that mixes sprinkles with coffee
    26  */
    27 public class Sprinkles extends CoffeDecorator {
    28 
    29     public Sprinkles(ICoffee decoratedCoffee) {
    30         super(decoratedCoffee);
    31     }
    32 
    33     public double getCost() {
    34         return super.getCost() + 1.2;
    35     }
    36 
    37     public String getIngredients() {
    38         return super.getIngredients() + ingredientSeparator + "Sprinkles";
    39     }
    40 
    41 }

    具体的装饰者类,继承抽象装饰者类,并具体实现抽象装饰者类的方法,达到将新的特性(milk/sprinkles)加到原来的类(coffee)的目的。

    public class Main {
    
        public static void main(String[] args) {
    
            ICoffee c = new SimpleCoffee();
            System.out.println("Cost: " + c.getCost() + "; Ingredients: " + c.getIngredients());
    
            c = new Milk(c);
            System.out.println("Cost: " + c.getCost() + "; Ingredients: " + c.getIngredients());
            
            c = new SimpleCoffee();
            c = new Sprinkles(c);
            System.out.println("Cost: " + c.getCost() + "; Ingredients: " + c.getIngredients());
    
            c=new SimpleCoffee();
            c = new Milk(new Sprinkles(c));
            System.out.println("Cost: " + c.getCost() + "; Ingredients: " + c.getIngredients());
    
        }
    
    }
    
    /*
     * output:
     * Cost: 1.0; Ingredients: Coffee
     * Cost: 1.5; Ingredients: Coffee,Milk
     * Cost: 2.2; Ingredients: Coffee,Sprinkles
     * Cost: 2.7; Ingredients: Coffee,Sprinkles,Milk
     */

    抽象类理解起来并不困难,而且相当实用,很多时候比创建子类更加灵活。在Java里java.io.BufferedReader/FileReader/Reader都有使用这个模式。

    以下情况使用Decorator模式

    1. 需要扩展一个类的功能,或给一个类添加附加职责。

    2. 需要动态的给一个对象添加功能,这些功能可以再动态的撤销。

    3. 需要增加由一些基本功能的排列组合而产生的非常大量的功能,从而使继承关系变的不现实。

    4. 当不能采用生成子类的方法进行扩充时。一种情况是,可能有大量独立的扩展,为支持每一种组合将产生大量的子类,使得子类数目呈爆炸性增长。另一种情况可能是因为类定义被隐藏,或类定义不能用于生成子类。

    优点:

    1. Decorator模式与继承关系的目的都是要扩展对象的功能,但是Decorator可以提供比继承更多的灵活性。

    2. 通过使用不同的具体装饰类以及这些装饰类的排列组合,设计师可以创造出很多不同行为的组合。

    缺点:

    1. 这种比继承更加灵活机动的特性,也同时意味着更加多的复杂性。

    2. 装饰模式会导致设计中出现许多小类,如果过度使用,会使程序变得很复杂。

    3. 装饰模式是针对抽象组件(Component)类型编程。但是,如果你要针对具体组件编程时,就应该重新思考你的应用架构,以及装饰者是否合适。当然也可以改变Component接口,增加新的公开的行为,实现“半透明”的装饰者模式。在实际项目中要做出最佳选择。

    参考:

    http://javapapers.com/design-patterns/decorator-pattern/

    http://www.cnblogs.com/god_bless_you/archive/2010/06/10/1755212.html

  • 相关阅读:
    微信小程序开发---各代码文件简介
    LeetCode71. 简化路径
    LeetCode70. 爬楼梯
    LeetCode69. x 的平方根
    LeetCode68. 文本左右对齐
    LeetCode剑指 Offer 09. 用两个栈实现队列
    LeetCode67. 二进制求和
    LeetCode66. 加一
    LeetCode65. 有效数字
    LeetCode64. 最小路径和
  • 原文地址:https://www.cnblogs.com/techyc/p/3599039.html
Copyright © 2011-2022 走看看