WX 搜寻:程序员个人修养 查看更多内容
装璜者模式(Decorator)
运行时扩大,远比编译期间的继承威力大。咱们将探讨如何应用对象组合的形式,做到在运行时装璜类。
利用继承设计子类的行为,是在编译时动态决定的,而且所有子类都会继承雷同的行为。然而,如果可能利用组合的做法扩大对象的行为,就能够在运行时动静地进行扩大,而不需批改现有代码。既然没有扭转现有代码,那么呈现 bug 的可能就不大幅升高。
设计准则
凋谢 - 敞开准则
类应该对外扩大开发,对批改敞开。
定义
装璜者模式动静地将责任附加到对象上。若要扩大性能,装璜者提供了比继承更有弹性的代替计划。
类图
代码实现
咱们以咖啡厅为例,来模仿一个装璜者模式的实现。
首先,咖啡厅售卖一种咖啡,这种咖啡原价是 ¥10,如果客户须要加糖的话,就须要加上糖的价格 ¥2,客户还能够抉择是否加牛奶,牛奶的价格是 ¥5。加糖或者咖啡都能够看做是对咖啡口味的装璜。
那么,在这个案例当中,咖啡就是被装璜者,糖和牛奶是两个装璜者,通过给咖啡装璜(这里是不同的口味,甜味或者牛奶味,亦或者两者都加),来售卖不同口味的咖啡,当然价格也会不同。
上面咱们用代码来实现:
package com.study.design.Decorator;
/**
* 被装璜者抽象类
*/
public abstract class Coffe {
/**
* 计算价格的办法
* @return
*/
protected abstract int cost();}
package com.study.design.Decorator;
/**
* 被装璜者对象
* 原味咖啡,售价 ¥10
*/
public class OriginalCoffe extends Coffe{
@Override
protected int cost() {return 10;}
}
package com.study.design.Decorator;
public abstract class Decorator extends Coffe{
// 被装璜者对象
protected Coffe coffe;
protected abstract int additional();}
package com.study.design.Decorator;
/**
* 装璜者
* 加糖 ¥2
*/
public class Sugar extends Decorator{public Sugar(Coffe coffe){this.coffe = coffe;}
@Override
protected int cost() {return coffe.cost() + additional();}
@Override
protected int additional() {return 2;}
}
package com.study.design.Decorator;
/**
* 装璜者
* 加牛奶 ¥5
*/
public class Milk extends Decorator{public Milk(Coffe coffe){this.coffe = coffe;}
@Override
protected int cost() {return coffe.cost() + additional();}
@Override
protected int additional() {return 5;}
}
package com.study.design.Decorator;
public class DecoratorTest {public static void main(String[] args) {OriginalCoffe originalCoffe = new OriginalCoffe();
System.out.println("原味咖啡价格:" + originalCoffe.cost());
Sugar sugar = new Sugar(originalCoffe);
System.out.println("加糖后的价格:" + sugar.cost());
Milk milk = new Milk(originalCoffe);
System.out.println("加牛奶后的价格" + milk.cost());
milk = new Milk(sugar);
System.out.println("加牛奶加糖后的价格:" + milk.cost());
}
}
相熟 AOP 的同学到这里应该会联想到,在装璜者中减少的新办法或者说性能,这不就像是
AOP
中的前置告诉、后置告诉么?是的!不过
AOP
底层是通过动静代理实现的,动静代理与装璜者模式本质区别就是,前者关注的是对代理对象行为管制,不同的代理对象实现被代理对象行为的不同的管制,并且这些代理对象很少有组合的可能。而后者侧重于对被装璜者性能的扩大。不同的装璜者为被装璜者削减不同的性能,并且这些装璜者能够任意嵌套组合。比方糖和牛奶能够同时增加。
Java I/O 中的装璜者模式
对于装璜者模式,最经典的就是 Java I/O
中的利用。理解了装璜者模式,再回头系统地看下无关 Java I/O
的源码就会晦涩很多。
以上展现了输出流的局部类图关系,输入流也是一样。但 Java I/O
也引出了装璜者模式的一个“毛病”:利用装璜者模式,经常会造成设计中有大量的小类,数量切实太多,可能会造成应用此 API
的开发人员的困扰。然而,如果理解了装璜者模式的原理,当前当应用他人的大量装璜的 API
时,就能够很容易的分别出他们的装璜者类时如何组织,以不便用包装形式获得想要的行为。
要点
- 所有被装璜者和装璜者须要继承自对立的父类或者实现同一个接口
- 装璜者须持有一个被装璜者接口类型的对象
- 装璜者能够在被装璜者前 / 后加上本人的行为,甚至将被装璜者的行为整个取代掉,而达到特定的目标
- 装璜者会导致设计中呈现许多小对象,如果适度应用,会让程序变得很简单
WX 搜寻:程序员个人修养 查看更多内容