Head First 设计模式之装饰器模式,因为参与,所以认同

2019-05-24 17:03:00 浏览数 (2)

装饰器模式

装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其结构。这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装。

装饰器模式解决的问题

动态地给一个对象添加一些额外的职责。就增加功能来说,装饰器模式相比生成子类更为灵活。

装饰器模式角色

Component(抽象组件):它是具体构件和抽象装饰类的共同父类,声明了在具体构件中实现的业务方法,它的引入可以使客户端以一致的方式处理未被装饰的对象以及装饰之后的对象,实现客户端的透明操作。

ConcreteComponent(具体组件):它是抽象构件类的子类,用于定义具体的构件对象,实现了在抽象构件中声明的方法,装饰器可以给它增加额外的职责(方法)。

Decorator(抽象装饰类):它也是抽象构件类的子类,用于给具体构件增加职责,但是具体职责在其子类中实现。它维护一个指向抽象构件对象的引用,通过该引用可以调用装饰之前构件对象的方法,并通过其子类扩展该方法,以达到装饰的目的。

ConcreteDecorator(具体装饰类):它是抽象装饰类的子类,负责向构件添加新的职责。每一个具体装饰类都定义了一些新的行为,它可以调用在抽象装饰类中定义的方法,并可以增加新的方法用以扩充对象的行为。

使用场景

咖啡店里咖啡中可以加不同的配料,摩卡、牛奶、糖、奶泡。手抓饼可以有不同的搭配,可以增加香肠、培根、里脊肉等等,计算增加不同的配料需要多少钱?

代码实现

之前我们讲过策略模式,如果使用策略模式,需要穷举列出所有的组合,种类越多,对于程序员来说是一种灾难性的打击。装饰器模式是一种不错的选择,能够很好的解决问题,增加一种配料或者装饰,只需要增加一个具体的装饰类即可,满足开闭原则。

代码语言:javascript复制
/**
 *
 * 装饰器模式
 * 抽象组件 -- 对应Coffee类
 */
public interface Coffee {
 public double cost();
}
代码语言:javascript复制
/**
 *
 * 具体组件 --无咖啡因
 *
 * 无咖啡因咖啡 8元
 *
 */
public class Decaf implements Coffee{
 public double cost() {
 return 8;
 }
}
代码语言:javascript复制
/**
 * Created by zengjianlu on 2018/2/23.
 *
 * 具体组件--浓咖啡
 *
 * 浓咖啡 10元
 */
public class Espresso implements Coffee{
 public Espresso(){
 System.out.println("1杯浓咖啡 10元");
 }
 public double cost() {
 return 10.0;
 }
}
代码语言:javascript复制
/**
 *
 *装饰类
 *
 */
public class Decorator implements Coffee{
 private Coffee coffee;
 public Decorator(Coffee coffee) {
 this.coffee = coffee;
 }
 public double cost() {
 return coffee.cost();
 }
}
代码语言:javascript复制
/**
 * 加摩卡 3元
 */
public class Mocha extends Decorator{
 public Mocha(Coffee coffee) {
 super(coffee);
 System.out.println("增加摩卡 3元");
 }
 public double cost(){
 return super.cost()   3;
 }
}
代码语言:javascript复制
/**
 * 加糖 两元
 */
public class Sugar extends Decorator{
 public Sugar(Coffee coffee) {
 super(coffee);
 System.out.println("增加糖 2元");
 }
 public double cost(){
 return super.cost()   2;
 }
}

定义一个抽象组件Coffee,两个具体组件,Decaf和Espresso,定义了装饰类Decorator,实现了抽象组件接口,拥有了抽象组件的行为。

以上代码,价格都是固定的,如果想要动态管理,可以通过数据库Mysql,或者动态配置中心Apollo进行管理。

代码语言:javascript复制
/**
 * 买了一杯浓咖啡 加摩卡 加糖
 * 测试类
 */
public class Test {
 public static void main(String[] args) {
 Coffee coffee = new Espresso();
 coffee = new Mocha(coffee);
 coffee = new Sugar(coffee);
 System.out.println("一共:"   coffee.cost());
 }
}

运行结果:

优缺点

优点:动态的给一个对象添加一些额外的职责,就扩展功能而言,比生成子类方式更为灵活。

缺点:装饰器模式虽然从数量级上减少了类的数量,但是为了要装饰,仍旧会增加很多的小类这些具体的装饰类的逻辑将不会非常的清晰,不够直观,容易令人迷惑。

生活中的装饰模式

房子装修,地板可以用瓷砖、木板,冰箱、电视可以使用不同的品牌。房子的主人可以根据自己的喜好,添加不同的装饰品,具有很强的灵活性。

服饰搭配,去逛商店,买衣服时,可以搭配不同小饰品,比如眼镜、帽子、围巾等等,有时候你只想买个衬衫,导购员可能会给你推荐一件毛衣,或者一件裤子,让你一起搭配,如果你自己也比较喜欢的话,可能三件都会购买。

我的启发

装饰器模式,让我们参与其中,自由的组合,形成自己的独特风格。因为参与,所以认同。

设计模式系列历史:

Head first 设计模式之策略模式,来源于生活,用之于生活

Head First 设计模式之观察者模式,你我都是发布者和订阅者

Head First 设计模式之单例模式,每个人都是唯一

0 人点赞