装饰者模式
增强原有对象,而不改变原有对象
- 定义:在不改变原有对象的基础上,将功能附加到对象上,提供了比继承更有弹性的替代方案(扩展原有对象功能)
- 类型:结构型
- 适用场景:
- 扩展一个类的功能或给一个类添加附加职责
- 动态的给一个对象添加功能,这些功能可以再动态的撤销
- 优点:
- 继承的有力补充,比继承灵活,不改变原有对象的情况下给一个对象扩展功能
- 通过使用不同装饰类以及这些装饰类的排列组合,可以实现不同的效果
- 符合开闭原则
- 缺点:
- 会出现更多的代码,更多的类,增加程序的复杂性
- 动态装饰时和多层装饰时会更复杂
- 相关设计模式:
- 装饰者模式和代理模式:装饰者模式主要关注在一个对象上动态的添加方法,而代理模式关注于控制对对象的访问,代理模式的代理类可以对其客户隐藏一个对象的具体信息,通常使用代理模式时,会在代理类中创建一个对象的实例,而装饰者模式的时候,通常会把原始对象作为一个参数传给装饰者的构造器
- 装饰者模式和适配器模式:都可以称为包装模式,装饰者和被装饰者可以实现相同的接口或者装饰者是被装饰者的子类,在适配器模式中,适配器和被适配的类具有不同的接口
coding
煎饼制作接口
public interface IBattercake { String getDesc(); int cost(); }
实体煎饼
public class Battercake implements IBattercake { public String getDesc() { return "煎饼"; } public int cost() { return 8; } }
抽象的装饰者
public abstract class AbstractDecorator implements IBattercake{ private IBattercake iBattercake; public AbstractDecorator(IBattercake iBattercake){ this.iBattercake = iBattercake; } protected abstract void doSomething(); public String getDesc() { return this.iBattercake.getDesc(); } public int cost() { return this.iBattercake.cost(); } }
实体的蛋装饰者
public class EggDecorator extends AbstractDecorator{ public EggDecorator(IBattercake iBattercake) { super(iBattercake); } @Override protected void doSomething() { } @Override public String getDesc() { return super.getDesc()+ " 加一个鸡蛋"; } @Override public int cost() { return super.cost() + 1; } }
实体的肠装饰者
public class SausageDecorator extends AbstractDecorator{ public SausageDecorator(IBattercake iBattercake) { super(iBattercake); } @Override public String getDesc() { return super.getDesc()+ " 加一根香肠"; } @Override public int cost() { return super.cost() + 2; } @Override protected void doSomething() { } }
测试
public class Test { public static void main(String[] args) { IBattercake aBattercake = new Battercake(); aBattercake = new EggDecorator(aBattercake); aBattercake = new EggDecorator(aBattercake); aBattercake = new SausageDecorator(aBattercake); System.out.println(aBattercake.getDesc() + " 销售价格:" + aBattercake.cost()); } }
=========运行结果==========
煎饼 加一个鸡蛋 加一个鸡蛋 加一根香肠 销售价格:12
UML
说明:通过构造函数,利用递归实现功能增加
实体煎饼实现煎饼制作接口,然后有个抽象的装饰角色,而鸡蛋和肠就是实体的装饰角色,我们可以先摊一个煎饼(new Battercake()),要加鸡蛋几个鸡蛋几根肠,可以将煎饼传给装饰者,让装饰者给其加料,无限次的扩展功能。
注意:其实抽象煎饼和抽象装饰者也非必须,要看实际场景是否需要抽象类扩展功能。
源码中的应用
- java.io.BufferedReader:如以下代码所示,Reader是一个抽象类,BufferedReader把Reader组合到自己的类中,它的构造器将Reader传入构造BufferedReader,BufferedReader就可以对Reader进行装饰
public class BufferedReader extends Reader { private Reader in; ... public BufferedReader(Reader in, int sz) { super(in); if (sz <= 0) throw new IllegalArgumentException("Buffer size <= 0"); this.in = in; cb = new char[sz]; nextChar = nChars = 0; } ...
- org.apache.ibatis.cache.Cache:可以看到这个文件夹下的类都是Cache的装饰者