装饰模式是在不必改变原类文件和使用继承的情况下,动态地扩展一个对象的功能。它是通过创建一个包装对象,也就是装饰来包裹真实的对象.以下情况使用Decorator模式
1. 需要扩展一个类的功能,或给一个类添加附加职责。
2. 需要动态的给一个对象添加功能,这些功能可以再动态的撤销。
3. 需要增加由一些基本功能的排列组合而产生的非常大量的功能,从而使继承关系变的不现实。
4. 当不能采用生成子类的方法进行扩充时。一种情况是,可能有大量独立的扩展,为支持每一种组合将产生大量的子类,使得子类数目呈爆炸性增长。另一种情况可能是因为类定义被隐藏,或类定义不能用于生成子类。
看了上面文字性的叙述头都晕了,下面以实例来讲解。我们都知道买奶茶可以添加各种配料,如下
这里只有了4种配料即可生成那么多种奶茶,如果我们用一个奶茶子类来存储该种奶茶的价格(价格为奶茶原价加上添加各个配料的前的和)和名称,则会派生出很多对应的子类,如果再为奶茶添加巧克力,布丁等配料,则又会添加许多子类,可以想象,每增加一种配料,对应的子类会增加很多。会导致类爆炸,也不好管理对应的子类。这里就可以使用装饰者模式来解决该问题。
1.定义被装饰者的对象接口
package com.longpo.decorator; /** * 被装饰者的对象接口 * */ public interface Drink { //奶茶名字 public String name(); //奶茶价格 public float price(); }
2.具体被装饰者的对象:奶茶
package com.longpo.decorator; /** * 具体的被装饰者对象:奶茶 * */ public class MikeTea implements Drink { @Override public String name() { return "奶茶"; } @Override public float price() { return 1f;//奶茶原价1元 } }
3.定义装饰者的父类
package com.longpo.decorator; /** *装饰者的父类 */ public abstract class Decorator implements Drink{ public Drink drink;//要装饰的对象 public Decorator(Drink drink) { this.drink=drink; } @Override public String name() { return drink.name(); } @Override public float price() { return drink.price(); } }
4.定义装饰者类:即配料
配料1:椰果类
package com.longpo.decorator; /** * 具体的装饰对象:椰果 */ public class Coconut extends Decorator{ public Coconut(Drink drink) { super(drink); } @Override public String name() { return "椰果"+super.name(); } @Override public float price() { return super.price()+0.8f;//椰果8毛 } }
配料2:珍珠类
package com.longpo.decorator; /** * 具体的装饰对象:珍珠 */ public class Pearl extends Decorator{ public Pearl(Drink drink) { super(drink); } @Override public String name() { return "珍珠"+super.name(); } @Override public float price() { return super.price()+0.5f;//珍珠5毛 } }
配料3:果条类
package com.longpo.decorator; /** * 具体的装饰对象:果条 */ public class Fruit extends Decorator{ public Fruit(Drink drink) { super(drink); } @Override public String name() { return "果条"+super.name(); } @Override public float price() { return super.price()+0.5f;//果条5毛 } }
配料4:红豆
package com.longpo.decorator; /** * 具体的装饰对象:红豆 */ public class RedBean extends Decorator{ public RedBean(Drink drink) { super(drink); } @Override public String name() { return "红豆"+super.name(); } @Override public float price() { return super.price()+1f;//红豆1元 } }
这样我们就写好了装饰者模式了,下面来测试一下装饰者模式
package com.longpo.decorator; public class DecoratorTest { public static void main(String[] args) { //首先弄杯奶茶 Drink drink=new MikeTea(); //奶茶里添加椰果 Coconut coconut=new Coconut(drink); //再添加红豆 RedBean redBean=new RedBean(coconut); System.out.println("第一杯奶茶为: "+redBean.name()+" 价格为: "+redBean.price()); //再弄杯奶茶 Drink drink1=new MikeTea(); //奶茶里添加果条 Fruit fruit=new Fruit(drink1); //再添加椰果 Coconut coconut1=new Coconut(fruit); //再添加红豆 RedBean redBean1=new RedBean(coconut1); //在添加珍珠 Pearl pearl=new Pearl(redBean1); System.out.println("-----------------------------"); System.out.println("第而杯奶茶为: "+pearl.name()+" 价格为: "+pearl.price()); } }
运行结果:
使用类装饰者模式,没添加一种配料我们主需要多添加一个配料的具体装饰者对象类就可以了。
通过上面的实际例子,已经发现了装饰者模式的好用之处了。学习了解装饰者设计模式是很有必要的,最常用的java的IO就使用了装饰者模式。