设计模式学习笔记:装饰者模式
Posted 滴滴哒滴哒
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了设计模式学习笔记:装饰者模式相关的知识,希望对你有一定的参考价值。
在之前面对系统扩展的方式,我们往往会选用继承的方式,在参数多的时候往往会造成子类数量的爆炸。如何在运行时动态扩展呢,这个时候装饰者模式应运而生。
一、装饰者模式的定义:
装饰模式是在不必改变原类文件和使用继承的情况下,动态地扩展一个对象的功能。它是通过创建一个包装对象,也就是装饰来包裹真实的对象。
二、 应用场景:
1.需要扩展一个类的功能,或给一个类添加附加职责。
2.需要动态的给一个对象添加功能,这些功能可以再动态的撤销。
3.需要增加由一些基本功能的排列组合而产生的非常大量的功能,从而使继承关系变的不现实。
4.当不能采用生成子类的方法进行扩充时。一种情况是,可能有大量独立的扩展,为支持每一种组合将产生大量的子类,使得子类数目呈爆炸性增长。另一种情况可能是因为类定义被隐藏,或类定义不能用于生成子类。
直白点说:装饰者模式使用类似于“什么”的“什么”的“什么”,这种情况下,形容词往往是可以动态增加的。
三、优点:
1. Decorator模式与继承关系的目的都是要扩展对象的功能,但是Decorator可以提供比继承更多的灵活性。
2. 通过使用不同的具体装饰类以及这些装饰类的排列组合,设计师可以创造出很多不同行为的组合。
四、缺点:
1. 这种比继承更加灵活机动的特性,也同时意味着更加多的复杂性。
2. 装饰模式会导致设计中出现许多小类,如果过度使用,会使程序变得很复杂。
3. 装饰模式是针对抽象组件(Component)类型编程。但是,如果你要针对具体组件编程时,就应该重新思考你的应用架构,以及装饰者是否合适。当然也可以改变Component接口,增加新的公开的行为,实现“半透明”的装饰者模式。在实际项目中要做出最佳选择。
五、设计原则:
类应该对外扩展开放,对修改关闭
多用组合,少用继承
示例:
一家咖啡店设计了一个系统,用于售卖咖啡产品,展示咖啡价格。咖啡品种有四种:HouseBlend、DarkRoast、Decaf以及Espresso,并且需要我们添加调味品,分别有:Milk,Soy,Mocha,Whip。以咖啡为主体,可以加入多种调味品。如果我们采用继承的方式去设计系统,子类会有HouseBlendWithMilkAndSoyAndMocha,DarkRoastWithWhip,可见子类会呈现排列组合式的增加,这样会给维护和后期扩展(若是价格变动)造成巨大影响。
换一种设计方式,我们将调味料作为Beverage里面的变量,这么设计父类,具体品种继承父类。
这是比较常见的一种设计方法。但是呢,如果后期添加删除调料,在扩展的时候我们还是要对这个类进行修改。有没有方法能够实现动态的增加,并且在扩展的时候不改动已有的类呢。
可见所有的组件全都继承了Beverage这个超类,为什么如此做呢?我们利用继承达到“类型匹配”,而不是用继承获得“行为”。我们这里的Beverage是一个抽象类(其实也可以用接口实现,但是考虑到抽象类中可以有方法体,这样我们咖啡中就不用重写其他方法了)。这种类型匹配主要作用于调料类的相互调用和调用咖啡类,这样实现就可以实现我们动态的扩展了。
Beverage类:
public abstract class Beverage
String description = "Unknown Beverage";
public String getDescription()
return description;
public abstract double cost();
CondimentDecorator类:
public abstract class CondimentDecorator extends Beverage
@Override
public abstract String getDescription();
咖啡类Espresso:
public class Espresso extends Beverage
public Espresso()
description = "Espresso";
//Espresso价格1.99
@Override
public double cost()
return 1.99;
咖啡类HouseBlend:
public class HouseBlend extends Beverage
public HouseBlend()
description = "House Blend Coffee";
//HouseBlend
@Override
public double cost()
return 0.89;
咖啡类DarkRoast:
public class DarkRoast extends Beverage
public DarkRoast()
description = "DarkRoast";
//DarkRoast价格0,99
@Override
public double cost()
return 0.99;
咖啡类Decaf:
public class Decaf extends Beverage
public Decaf()
description = "Decaf";
//Decaf价格1.05
@Override
public double cost()
return 1.05;
调料类Whip:
public class Whip extends CondimentDecorator
//方便实现引用其他Beverage类,然后把其作为构造器的参数
Beverage beverage;
public Whip(Beverage beverage)
this.beverage = beverage;
@Override
public String getDescription()
return beverage.getDescription() + ",Whip";
@Override
public double cost()
return 0.1 + beverage.cost();
调料类Mocha:
public class Mocha extends CondimentDecorator
Beverage beverage;
public Mocha(Beverage beverage)
this.beverage = beverage;
@Override
public String getDescription()
return beverage.getDescription() + ",Mocha";
@Override
public double cost()
return 0.2 + beverage.cost();
调料类Soy:
public class Soy extends CondimentDecorator
Beverage beverage;
public Soy(Beverage beverage)
this.beverage = beverage;
@Override
public String getDescription()
return beverage.getDescription() + ",soy";
@Override
public double cost()
return 0.15 + beverage.cost();
调料类Milk:
public class Milk extends CondimentDecorator
Beverage beverage;
public Milk(Beverage beverage)
this.beverage = beverage;
@Override
public String getDescription()
return beverage.getDescription() + ",Milk";
@Override
public double cost()
return 0.10 + beverage.cost();
测试类:
public class StarbuzzCoffee
public static void main(String[] args)
Beverage beverage = new Espresso();
System.out.println(beverage.getDescription() + beverage.cost());
Beverage beverage1 = new DarkRoast();
beverage1 = new Mocha(beverage1);
beverage1 = new Mocha(beverage1);
beverage1 = new Whip(beverage1);
System.out.println(beverage1.getDescription() + beverage1.cost());
Beverage beverage2 = new HouseBlend();
beverage2 = new Soy(beverage2);
beverage2 = new Mocha(beverage2);
beverage2 = new Whip(beverage2);
System.out.println(beverage2.getDescription() + beverage2.cost());
结果:
但是我们也可以看到,我们类的数量得到了很大的增长。如果我们不需要进行动态扩展,其实应用第二个方法就可以。
以上是关于设计模式学习笔记:装饰者模式的主要内容,如果未能解决你的问题,请参考以下文章