装饰着模式(Decorator Pattern)
装饰者模式是动态的将责任附加到对象上,若要扩展功能,装饰者提供了比继承更有弹性的替代方案。
简单的说,装饰者模式由三部分组成,分别是基础抽象类,可以被装饰者包装的类、装饰者类,后两种类均是基础抽象类的子类,但是里面的方法对于基础类有更多的扩展,最终使用,均是使用的基础类进行操作,因此,无论怎么包装,出来的对象都可以使用基础类接收。同时,可以被装饰者包装的类一般使用无参构造,而装饰者类则是使用基础类作为入参的构造函数。
举个例子,一杯咖啡,他的名字和售价,就可能因为添加不同的调料而导致售价和名称不同,并且调料的组合方式也存在多种。
在JDK中,I/O就是使用的装饰着模式,如下图所示,InputStrem是装饰者模式的抽象组件,红色标记的4个是可以被装饰者包起来的具体组件,而绿色部分,就是具体的装饰者。
试用装饰者模式有一个缺点,就是代码中会存在大量的小类,可能会给使用API人造成困扰。
那么,就根据上述举的例子,来写一下装饰者模式
首先,创建一个抽象类,抽象类中包含一个获取名称的方法和一个获取价格的抽象方法
package lcl.mm.pattern.decorator; public abstract class Beverage { String desc = "Unknow Beverge"; public String getDesc(){ return desc; } public abstract int cost(); }
然后,分别创建两个可以被装饰者包装的A咖啡类和B咖啡类,类中一个无参构造函数和一个获取价格的函数,无参构造函数中直接返回咖啡的名称,而价格直接返回自身的价格。
package lcl.mm.pattern.decorator; public class CofeeA extends Beverage{ public CofeeA(){ desc = "CofeeA"; } @Override public int cost() { return 5; } }
package lcl.mm.pattern.decorator; public class CofeeB extends Beverage{ public CofeeB(){ desc = "CofeeB"; } @Override public int cost() { return 10; } }
接下来就创建两个装饰者类调味料A和调味料B,类中包含有参构造函数、获取名称方法和获取售价方法,在构造函数中,将Beverage传入,获取名称时,在原有Beverage的名称上加上该调味料的名称,而获取价格的方法是在原有Beverage的售价上加上该调味料的价格、
package lcl.mm.pattern.decorator; public class CondimentA extends Beverage { Beverage beverage; public CondimentA(Beverage beverage){ this.beverage = beverage; } public String getDesc(){ return beverage.getDesc() + ",加调味料CondimentA"; } @Override public int cost() { return 2 + beverage.cost(); } }
package lcl.mm.pattern.decorator; public class CondimentB extends Beverage { Beverage beverage; public CondimentB(Beverage beverage){ this.beverage = beverage; } public String getDesc(){ return beverage.getDesc() + ",加调味料CondimentB"; } @Override public int cost() { return 1 + beverage.cost(); } }
如上,装饰者模式就写完了,接下来进行测试:
@Test public void decoretorTest(){ Beverage beverage1 = new CofeeA(); log.info("Beverage=={}售价:${}",beverage1.getDesc(),beverage1.cost()); Beverage beverage = new CofeeB(); log.info("Beverage=={}售价:${}",beverage.getDesc(),beverage.cost()); beverage = new CondimentA(beverage); log.info("Beverage=={}售价:${}",beverage.getDesc(),beverage.cost()); beverage = new CondimentB(beverage); log.info("Beverage=={}售价:${}",beverage.getDesc(),beverage.cost()); beverage = new CondimentA(beverage); log.info("Beverage=={}售价:${}",beverage.getDesc(),beverage.cost()); }
输出:
------------------------------------------------------------------
-----------------------------------------------------------
---------------------------------------------
朦胧的夜 留笔~~
-----------------------------------------------------------
---------------------------------------------
朦胧的夜 留笔~~