概述
装饰模式(Decorator Pattern)是指动态的给一个对象添加一些额外的职责,就增加功能来说,装饰模式比生成子类更灵活。
看下它的结构类图
下面举个例子,代码实现一个这样的场景,我们早上去煎饼摊买煎饼的场景,煎饼可以加蛋和香肠(扩展)
首先实现继承来实现看看
Battercake-煎饼类
public class Battercake { protected String getMsg() { return "煎饼"; } public int getPrice() { return 5; } }
使用继承BattercakeWithEgg-加鸡蛋
public class BattercakeWithEgg extends Battercake{ protected String getMsg() { return super.getMsg() + "加一个鸡蛋"; } public int getPrice() { return super.getPrice() + 1; } }
加香肠
public class BattercakeWithEggAndSausage extends BattercakeWithEgg{ protected String getMsg() { return super.getMsg() + "加一个香肠"; } public int getPrice() { return super.getPrice() + 2; } }
测试
public class BattercakeTest { public static void main(String[] args) { Battercake battercake = new Battercake(); System.out.println(battercake.getMsg() + ",总价格:" + battercake.getPrice()); Battercake battercakeWithegg = new BattercakeWithEgg(); System.out.println(battercakeWithegg.getMsg() + ",总价格:" + battercakeWithegg.getPrice()); Battercake battercakeWithEggAndSausage = new BattercakeWithEggAndSausage(); System.out.println(battercakeWithEggAndSausage.getMsg() + ",总价格:" + battercakeWithEggAndSausage.getPrice()); } }
结果
我们可以看出来继承并不灵活,假如我比较额要加两个蛋,两个香肠怎么办,继续添加子类?显然这样不过灵活
接下来使用装饰模式
抽象类Battercake,可以对应上面类图Component
public abstract class Battercake { public abstract String getMsg(); public abstract int getPrice(); }
具体对象BaseBattercake,不加任何扩展的煎饼
public class BaseBattercake extends Battercake{ @Override public String getMsg() { return "煎饼"; } @Override public int getPrice() { return 5; } }
定义抽象装饰类BattercakeDecorator
public abstract class BattercakeDecorator extends Battercake{ private Battercake battercake; public BattercakeDecorator(Battercake battercake) { this.battercake = battercake; } @Override public String getMsg() { return this.battercake.getMsg(); } @Override public int getPrice() { return this.battercake.getPrice(); } }
具体装饰类-加鸡蛋的装饰类EggDecorator
public class EggDecorator extends BattercakeDecorator { public EggDecorator(Battercake battercake) { super(battercake); } @Override public String getMsg() { return super.getMsg() + "+一个鸡蛋"; } @Override public int getPrice() { return super.getPrice() + 1; } }
具体装饰类-加香肠的装饰类SausageDecorator
public class SausageDecorator extends BattercakeDecorator { public SausageDecorator(Battercake battercake) { super(battercake); } @Override public String getMsg() { return super.getMsg() + "+一个香肠"; } @Override public int getPrice() { return super.getPrice() + 2; } }
测试类,加2个鸡蛋1根香肠
public class BattercakeDecoratorTest { public static void main(String[] args) { Battercake battercake = new BaseBattercake(); battercake = new EggDecorator(battercake); battercake = new EggDecorator(battercake); battercake = new SausageDecorator(battercake); System.out.println(battercake.getMsg() + ",总价:" + battercake.getPrice()); } }
结果
会发现基础类很简单,所有的装饰方法与基础方法分开管理,需要的的时候只需要装饰上就好,就好比一个人可以穿很多种类的衣服,但是我们没必要在Person类中把这些装饰的功能增加进去,而是在需要时动态添加
那么我们什么时候该用装饰模式呢,当我们系统需要新的功能的时候,是向旧的类中添加新的代码,这些新的代码装饰了原有类的核心职责或主要行为,如果在主类中增加新的字段和新的方法无疑增加了类的复杂度,比如期初我们只有一个煎饼类,如果加鸡蛋香肠那么原本的类就会很复杂,新加的东西只是为了满足某个特殊需求,装饰模式提供了很好的解决方案,他把每一个要装饰的功能放在单独的类中,让这个类包装所要装饰的类,所有当有特殊需求时客户端可以有选择、有顺序的选择使用装饰功能
装饰模式的好处就是有效的把类的核心职责和装饰功能分开