1.定义
动态的给一个对象添加一个额外的职责,就增加功能来说,装饰模式比生成子类更为灵活。
2.解决问题
——奖金计算
不用模式的解决方案
public class Prize {
public double calcPrize(String user, Date begin, Date end) {
double prize = 0.0;
// 计算当月业务奖金,所有人都会计算
prize = this.monthPrize(user, begin, end);
// 计算累计奖金
prize += this.calcPrize(user, begin, end);
// 需要判断该人员是普通人员还是业务经理,团队奖金只有业务经理才有
if(this.isManager(user)) {
prize += this.groupPrize(user, begin, end);
}
return prize;
}
private double groupPrize(String user, Date begin, Date end) {
return 0;
}
private boolean isManager(String user) {
return false;
}
private double monthPrize(String user, Date begin, Date end) {
return 0;
}
}
使用装饰模式来解决问题
public abstract class Component {
public abstract double calcPrize(String user, Date begin, Date end);
}
public abstract class Decorator extends Component {
protected Component c;
public Decorator(Component c) {
super();
this.c = c;
}
public double calcPrize(String user, Date begin, Date end) {
// 转调组件对象的方法
return c.calcPrize(user, begin, end);
}
}
public class MonthPrizeDecorator extends Decorator {
public MonthPrizeDecorator(Component c) {
super(c);
}
public double calcPrize(String user, Date begin, Date end) {
// 先获取前面运算出来的奖金
double money = super.calcPrize(user, begin, end);
// 然后计算当月业务奖金
double prize = 0.0;
return money + prize;
}
}
public class SumPrizeDecorator extends Decorator {
public SumPrizeDecorator(Component c) {
super(c);
}
public double calcPrize(String user, Date begin, Date end) {
// 先获取前面运算出来的奖金
double money = super.calcPrize(user, begin, end);
// 然后计算累计奖金
double prize = 1000000 * 0.001;
return money + prize;
}
}
public class Client {
public static void main(String[] args) {
Component c1 = new ConcreteComponent();
Decorator d1 = new MonthPrizeDecorator(c1);
Decorator d2 = new SumPrizeDecorator(d1);
double userA = d1.calcPrize("a", null, null);
double userB = d2.calcPrize("b", null, null);
}
}
案例说明:
3.模式讲解
由于奖金的计算方式经常发生变动,几乎每个季度都有小调整,每年都有大调整,这要求软件实现要足够灵活,能够很快进行相应的调整和修改,否则就不能满足实际业务的需要。把问题抽象以下:设若有一个计算奖金的对象,现在需要能够灵活的给它增加和减少功能,还需要能够动态的组合功能,每个功能就相当于在计算奖金的某个部分。
则问题就是:如何能透明地给一个对象增加功能,并实现功能的动态组合。
解决思路
所谓透明地给一个对象增加功能,即给一个对象增加功能,但不能让这个对象知道,也就不是不去改动这个对象,而实现给一个对象透明的增加功能,这就实现了功能的动态组合。
实现透明地给一个对象增加功能,即要扩展对象功能,可使用继承。
为了能够实现和原来使用被装饰对象的代码无缝结合,通过顶一个抽象类,让这个类实现与被装饰对象相同的接口,然后在具体实现类中,转调被装饰的独享,在转调前后添加新的功能,这就实现了给装饰对象增加功能。
在转调的时候,如果觉得被装饰对象的功能不再被需要,还可以直接替换,也就是不在转调,而是在装饰杜相忠完成全新的实现。
示例代码
public abstract class Component {
public abstract void operation();
}
public class ConcreteComponent extends Component {
public void operation() {
// 相应的功能处理
}
}
public abstract class Decorator extends Component {
protected Component component;
public Decorator(Component component) {
super();
this.component = component;
}
public void operation() {
// 转发请求给组件独享,可以在转发前后执行一些附加动作
component.operation();
}
}
public class ConcreteDecoratorA extends Decorator {
public ConcreteDecoratorA(Component component) {
super(component);
}
private String addedState;
public void operation() {
// 调用父类的方法,可以在调用前后执行一些附加动作
// 在这里进行处理的时候,可以使用添加的状态
super.operation();
}
}
public class ConcreteDecoratorB extends Decorator {
public ConcreteDecoratorB(Component component) {
super(component);
}
private void addBehavior() {
// 需要添加的职责实现
}
public void operation() {
// 调用父类的方法,可以在调用前后执行一些附加动作
super.operation();
this.addBehavior();
}
}
应用范围
装饰模式能够实现动态添加,是从一个对象外部来给对象添加功能,相当于改变了对象的外观。当装饰后,从外部使用系统的角度,就不再是使用原来是的那个类,而是使用被一系列装饰器包装过后的对象。
对象组合
在面向对象的设计中,有一条基本规则就是"尽量使用对象组合,而不是继承"来扩展和复用功能。装饰模式就是这个规则。
假如有一个对象A,实现了a1方法,而C1对象想要扩展A的功能,给它增加一个c1的方法。
使用继承:
public class A {
public void a1() {}
}
public class C extends A {
public void c1() {}
}
使用对象组合:
public class C {
private A a = new A();
public void a1() {
a.a1();
}
public void c1() {}
}
装饰器和组件类的关系
装饰器是用来修饰组件的,装饰器一定要实现和组件类一致的接口。组件类是不知道装饰器的存在的,装饰器为组件提那家功能是一种透明的包装。
装饰器的应用—— I/O流
InputStream就相当于装饰模式中的Component;
FileInputStream、ObjectInputStream、StringBufferInputStream这些对象都是直接继承InputStream,这些相当于装饰模式中的ConcreteComponent,是可以被装饰器装饰的对象;
FilterInputStream相当于装饰器模式中的Decorator,而它的子类DataInputStream、BufferedInputStream、LinkNumberInputStream和PushbackInputStream 相当于装饰器模式中的ConcreteDecorator。
装饰模式的优缺点:
优点:比继承更灵活、更容易复用功能、简化高层定义
缺点:会产生很多细粒度对象
4.思考
装饰模式的本质是:动态组合
动态是手段,组合才是目的。这里组合有两个意思,一个是动态功能的组合,也就是动态进行装饰器的组合;另一个是指对象组合,通过对象组合来实现为装饰对象透明的增加功能。
何时选用装饰模式模式
如果想:在不影响其他对象的情况下,以动态、透明的方式给对象添加职责,可以使用装饰模式。
如果:不适合使用子类来扩展的时候,可以使用装饰模式。
说明:笔记内容摘自《研磨设计模式》陈臣,王斌
转载于:https://blog.51cto.com/sauron/1230136