每天一个设计模式:装饰者模式

每天一个设计模式:装饰者模式

请注意,本文编写于  1,180  天前,最后修改于  1,180  天前,其中某些信息可能已经过时。

装饰者模式

1、意图

动态的给一个对象添加额外的功能,装饰者模式是一种用于代替继承的技术,无须通过继承增加子类就能扩展对象的新功能。使用对象的关联关系代替继承关系,更加灵活,同时避免类型体系的快速膨胀。

2、适用环境

  1. 在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责
  2. 处理那些可以撤销的职责
  3. 当不能采用生成子类的方法进行扩充时。一种情况是,可能有大量独立的扩展,为支持每一种组合将产生大量的子类,使得子类的数量爆炸增长。另一种情况可能是因为类定义被隐藏,或类定义不能用于生成子类。

3、参与者

  1. Component(抽象构件角色)

    真实对象和装饰对象有相同的接口,这样,客户端对象就能够以与真实对象相同的方式同装饰对象进行交互。

  2. ConcreteComponent(具体构件角色,即真实对象)

    IO流中的FileInputStream、FileOutputStream

  3. Decorator(装饰角色)

    持有一个抽象构件的引用。装饰对象接受所有客户端的请求,并把这些请求转发给真实的对象。这样,就能在真实对象调用前后增加新的功能。

  4. ConcreteDecorator(具体装饰角色)

    负责给构件对象增加新的责任。

4、类图

5、涉及角色

  1. 抽象组件:定义一个抽象接口,来规范准备附加功能的类。
  2. 具体组件:将要被附加功能的类,实现抽象构件角色接口。
  3. 抽象装饰者:持有对具体构件角色的引用并定义与抽象构件角色一致的接口。
  4. 具体装饰:实现抽象装饰者角色,负责对具体构件添加额外功能。

6、代码举例

对已有的业务逻辑进一步的封装,使其增加额外的功能,如Java中的IO流就使用了装饰者模式,用户在使用的时候,可以任意组装,达到自己想要的效果。 举个栗子,我想吃三明治,首先我需要一根大大的香肠,我喜欢吃奶油,在香肠上面加一点奶油,再放一点蔬菜,最后再用两片面包夹一下,很丰盛的一顿午饭,营养又健康。那我们应该怎么来写代码呢? 首先,我们需要写一个Food类,让其他所有食物都来继承这个类,看代码:

public class Food {

   private String food_name;

   public Food() {
   }

   public Food(String food_name) {
       this.food_name = food_name;
   }

   public String make() {
       return food_name;
   };
}

代码很简单,我就不解释了,然后我们写几个子类继承它:

//面包类
public class Bread extends Food {

   private Food basic_food;

   public Bread(Food basic_food) {
       this.basic_food = basic_food;
   }

   public String make() {
       //加入子类实现的具体逻辑
       return basic_food.make()+"+面包";
   }
}

//奶油类
public class Cream extends Food {

   private Food basic_food;

   public Cream(Food basic_food) {
       this.basic_food = basic_food;
   }

   public String make() {
       //加入子类实现的具体逻辑
       return basic_food.make()+"+奶油";
   }
}

//蔬菜类
public class Vegetable extends Food {

   private Food basic_food;

   public Vegetable(Food basic_food) {
       this.basic_food = basic_food;
   }

   public String make() {
       //加入子类实现的具体逻辑
       return basic_food.make()+"+蔬菜";
   }

}

这几个类都是差不多的,构造方法传入一个Food类型的参数,然后在make方法中加入一些自己的逻辑,如果你还是看不懂为什么这么写,不急,你看看我的Test类是怎么写的,一看你就明白了 。

public class Test {
   public static void main(String[] args) {
       Food food = new Bread(new Vegetable(new Cream(new Food("香肠"))));
       System.out.println(food.make());
   }
}

如果用继承去实现的话,会产生什么样的结果呢?

首先,肯定是需要创建一个Food类,然后去创建Food类的子类叫香肠奶油蔬菜三明治,但是如果我每天都不想吃同一种菜,那么每天都需要创建一个子类去继承Food类,这样下去肯定是会产生子类爆炸的。而利用装饰者模式,比如我个人就偏爱吃蔬菜、奶油、鸡蛋、面包等这几个具体的类,那么我们只需要对这几种类进行继承或者实现即可,而不用单独去一一创建组合的子类,具体吃啥则有我们自己对基本food进行自由装饰。

本文由 Sanarous 创作,如果您觉得本文不错,请随意赞赏
采用 知识共享署名4.0 国际许可协议进行许可,转载前请务必署名
本文链接:https://bestzuo.cn/posts/decorator-pattern.html
最后更新于:2019-04-03 20:44:39

切换主题 | SCHEME TOOL