系统架构设计——设计模式之装饰者模式

时间:2021-03-06 21:58:34

许多模式是长期经验的实证,可通过提供扩展的方法来保护代码免于被修改。接下来我将介绍一下一个完全遵循开放-关闭原则的设计模式——装饰者模式它可以给爱用继承的人一个全新的设计眼界。——Head First 设计模式

装饰者模式的定义

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

应用场景

与之前的策略模式不同,装饰者模式是用来解决多方案的组合问题的。试想一下五个策略的任意组合有多少种呢?答案是: 251=31 种组合
策略模式的处理只能是实现单个的策略,而非他们的组合。那么,这时候就需要用上装饰者模式了。其实在java中,i/o的封装就是用的这种模式。

结构图如下

系统架构设计——设计模式之装饰者模式

代码表示

现在我们从一个实际问题出发,体会一下装饰者模式的好处。
现实场景:在一家面馆中,面分为细面和宽面两种,价格分别为2元、2.5元。加入的料分为排骨和牛肉,价格分别为4元、4.5元。下面我们就使用装饰者模式实现他们的任意组合,并且如果加入别的种类,也不需要修改原先的代码。

1. 抽象构件(Component)角色,Noodles

package com.xiaocao.decorator;
/**
* 顶层抽象类
* 具有面的描述信息,和抽象的计算价格方法
* @author 木小草
*
*/

public abstract class Noddles {
String description = "Unknown noodles";
public String getDescription() {
return description;
}
public abstract double cost();
}

2. 具体构件(Concrete Component)角色,宽面和细面

package com.xiaocao.decorator;
/**
* 面A的实现类,宽面不好描述,索性用A来代替
* @author 木小草
*
*/

public class NoodlesA extends Noddles{
public NoodlesA() {
description = "宽面";
}
public double cost() {
return 2.5;
}
}
/*=============================================*/
package com.xiaocao.decorator;
/**
* 面B的实现类
* @author 木小草
*
*/

public class NoodlesB extends Noddles{
public NoodlesB() {
description = "细面";
}
public double cost() {
return 2.0;
}

}

3. 装饰(Decorator)角色,各种料的抽象

package com.xiaocao.decorator;

/**
* 这是装饰者共同实现的接口,也可以是抽象类
* @author 小草
*
*/

public abstract class CondimentDecorator extends Noddles{
public abstract String getDescription();
}

4. 具体装饰(Concrete Decorator)角色,牛肉和排骨

package com.xiaocao.decorator;
/**
* 装饰者的实现类,实现装饰部分,与其他装饰者没有关系
* 如果添加装饰者可直接添加类即可,无需修改原有代码
* @author 木小草
*
*/

public class Beef extends CondimentDecorator{
// 这一步很重要,这是装饰者模式的重要实现方式,即利用多态
Noddles beverage;
public Beef(Noddles beverage) {
this.beverage = beverage;
}
public String getDescription() {
return beverage.getDescription() + ",牛肉";
}
public double cost() {
return 4.0 + beverage.cost();
}

}
/*================================================*/
package com.xiaocao.decorator;
/**
*
* @author 木小草
*
*/

public class Chops extends CondimentDecorator{

Noddles beverage;
public Chops(Noddles beverage) {
this.beverage = beverage;
}

public String getDescription() {
return beverage.getDescription() + ",排骨";
}
public double cost() {
return 3.5 + beverage.cost();
}
}

5. 测试

package com.xiaocao.decorator;

public class Test {
public static void main(String[] args) {
// new一个宽面
Noddles noodles = new NoodlesA();
// 利用多态,将chops中的noodles被上一步的宽面赋值,相当于用chops装饰了上一步的宽面
noodles = new Chops(noodles);
// 利用多态,将上一步的排骨宽面赋值给beef的noodles,相当于用beef又装饰了一遍
noodles = new Beef(noodles);
// 输出描述信息和计算价格一样,先调用beef的方法,然后通过noodles属性,一步步调用上一步的方法,实现动态装饰
System.out.println(noodles.getDescription() + " $" + noodles.cost());
}
}

运行结果如下
系统架构设计——设计模式之装饰者模式

装饰者模式的认识

  1. 装饰者模式严格遵循了开放-关闭原则,如果我们想现在加入一个炸酱料,只需要新建一个炸酱的类继承Noodles,实现其中的方法即可。无需改动任何其他的类。如果在服务器运行中,服务器也不用重新编译,只需要重启一下就行。如果想实现连服务器也不用重启,则需要我们用到其他的知识实现,在这里就不讨论了。
  2. 装饰者模式充分利用了多态的特性,在分离了装饰行为和业务组合的同时,也让他们之间并没有具体感知。换句话说就是,每一个装饰者中的noodles属性成员只是一个接口,并不知道具体是宽面还是细面还是牛肉的等等。从这个层面讲,这也体现了单一职责原则和高内聚低耦合的设计思想。
  3. 还是那句话,”它可以给爱用继承的人一个全新的设计眼界“。

优缺点

优点

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

缺点

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

注意:转载请标明,转自itboy-木小草
尊重原创,尊重技术。