装饰者模式的定义
动态地将责任附加到对象上,若要扩展功能,装饰者提供了比继承更有弹性的替代方案
装饰者模式的UML类图
一般来说装饰者模式有下面几个参与者:
- Component:装饰者和被装饰者共同的父类,是一个接口或者抽象类,用来定义基本行为
- ConcreteComponent:定义具体对象,即被装饰者
- Decorator:抽象装饰者,继承自Component,从外类来扩展ConcreteComponent。对于ConcreteComponent来说,不需要知道Decorator的存在,Decorator是一个接口或抽象类
- ConcreteDecorator:具体装饰者,用于扩展ConcreteComponent
注:装饰者和被装饰者对象有相同的超类型,因为装饰者和被装饰者必须是一样的类型,这里利用继承是为了达到类型匹配,而不是利用继承获得行为。
利用继承设计子类,只能在编译时静态决定,并且所有子类都会继承相同的行为;利用组合的做法扩展对象,就可以在运行时动态的进行扩展。装饰者模式遵循开放-关闭原则:类应该对扩展开放,对修改关闭。利用装饰者,我们可以实现新的装饰者增加新的行为而不用修改现有代码,而如果单纯依赖继承,每当需要新行为时,还得修改现有的代码。
example:
/** * @author yaoshw */ public class TestMyIdea { public static void main(String[] args) { //不添加任何调料的饮料A Beverage beverage = new APart(); System.out.println("Apart:" + beverage.getDescription() + "," + beverage.cost()); //添加摩卡调料的饮料B Beverage beverage1 = new Mocha(new BPart()); System.out.println("Bpart:" + beverage1.getDescription() + "," + beverage1.cost()); //添加双份摩卡的饮料C Beverage beverage2 = new Mocha(new Mocha(new CPart())); System.out.println("Cpart:" + beverage2.getDescription() + "," + beverage2.cost()); //添加一份摩卡、一份豆浆的饮料D Beverage beverage3 = new Soy(new Mocha(new DPart())); System.out.println("Dpart:" + beverage3.getDescription() + "," + beverage3.cost()); } } /** * 抽象类,相当于Component:cost方法和getDescription方法 */ abstract class Beverage { String description = "UnKnownBeverage"; public String getDescription() { return description; } public abstract double cost(); } abstract class CondimentDerector extends Beverage { @Override public abstract String getDescription(); } /** * 具体装饰者:摩卡 */ class Mocha extends CondimentDerector { /** * 保留基类的引用,以便于组合装饰者行为 */ Beverage beverage; public Mocha(Beverage beverage) { this.beverage = beverage; } @Override public double cost() { return beverage.cost() + 2; } @Override public String getDescription() { return beverage.getDescription() + ",monka"; } } /** * 具体装饰者:豆浆 */ class Soy extends CondimentDerector { Beverage beverage; public Soy(Beverage beverage) { this.beverage = beverage; } @Override public double cost() { return beverage.cost() + 3; } @Override public String getDescription() { return beverage.getDescription() + "soy"; } } /** * 调料A */ class APart extends Beverage { public APart() { description = "Apart"; } @Override public double cost() { return 19.5; } } /** * 调料B */ class BPart extends Beverage { public BPart() { description = "Bpart"; } @Override public double cost() { return 20.5; } } /** * 调料C */ class CPart extends Beverage { public CPart() { description = "Cpart"; } @Override public double cost() { return 21.5; } } /** * 调料D */ class DPart extends Beverage { public DPart() { description = "Dpart"; } @Override public double cost() { return 22.5; } }