1.装饰模式的概念
动态的给一个对象添加一些额外的职责,同时又不改变其结构。使用对象的关联关系代替继承关系,更加灵活,同时避免类型体系的快速膨胀。就增加功能来说,装饰模式比生成子类更加灵活。
2.装饰模式的结构
- 抽象组件角色(Component):定义一个对象接口,可以给这些对象动态的添加职责。
- 具体组件角色(ConcreteComponent):被装饰者,定义了一个将要被装饰增加功能的类,也可以给这个对象添加一些职责。
- 抽象装饰器(Decorator):维持一个指向构件Component对象的实例,并定义一个与抽象组件角色Component接口一致的接口。
- 具体装饰器角色(ConcreteDecoratorA/ConcreteDecoratorB):向组件添加职责。
3.装饰模式的基本代码实现
Component类:
package com.jxs.decorator;
/**
* Created by jiangxs on 2018/5/3.
*/
public abstract class Component {
public abstract void operation();
}
ConcreteComponnet类:
package com.jxs.decorator;
/**
* Created by jiangxs on 2018/5/3.
*/
public class ConcreteComponent extends Component {
@Override
public void operation() {
System.out.println("具体对象的操作");
}
}
Decorate类:
package com.jxs.decorator;
/**
* Created by jiangxs on 2018/5/3.
*/
public class Decorator extends Component {
protected Component component;
public void setComponent(Component component) {
this.component = component;
}
@Override
public void operation() {
if (component != null) {
component.operation();
}
}
}
ConcreteDecoratorA类:
package com.jxs.decorator;
/**
* Created by jiangxs on 2018/5/3.
*/
public class ConcreteDecoratorA extends Decorator {
private String addedState;
@Override
public void operation() {
// 首先运行原Component的operation()
// 在执行本类的功能,如addedState,相当于对原Component进行了装饰
super.operation();
addedState = "New State";
System.out.println("具体装饰对象A的操作");
}
}
ConcreteDecoratorB类:
package com.jxs.decorator;
/**
* Created by jiangxs on 2018/5/3.
*/
public class ConcreteDecoratorB extends Decorator {
@Override
public void operation() {
// 首先运行原Component的operation()
// 再执行本类的功能,如AddedBehavior(),相当于对原Component进行了装饰
super.operation();
AddedBehavior();
System.out.println("具体装饰对象B的操作");
}
// 本类特有的方法,以区分ConcreteDecoratorA
private void AddedBehavior() {
System.out.println("AddedBehavior Operation");
}
}
客户端代码:
package com.jxs.decorator;
/**
* Created by jiangxs on 2018/5/3.
*/
public class DecoratorClient {
public static void main(String[] args) {
ConcreteComponent concreteComponent = new ConcreteComponent();
ConcreteDecoratorA decoratorA = new ConcreteDecoratorA();
ConcreteDecoratorB decoratorB = new ConcreteDecoratorB();
// 装饰的方法是:
// 首先用ConcreteComponent实例化对象concreteComponent
// 然后用ConcreteecoratorA的实例化对象decoratorA来包装concreteComponent
// 再用ConcreteDecoratorB的对象decoratorB包装decoratorA,最终执行Operation
decoratorA.setComponent(concreteComponent);
decoratorB.setComponent(decoratorA);
decoratorB.operation();
}
}
运行结果:
具体对象的操作
具体装饰对象A的操作
AddedBehavior Operation
具体装饰对象B的操作
Process finished with exit code 0
4.装饰模式的应用
以《大话设计模式》中小菜穿衣服的搭配为例,在这个例子中,人穿各种衣服,其中人就是ConcreteComponent,而服饰就是一个Decorator,各种具体的衣服就是ConcreteDecorator.
小菜穿衣搭配的代码示例:
Person类(ConcreteComponent):
package com.jxs.decoratorExample;
/**
* Created by jiangxs on 2018/5/3.
*/
public class Person {
private String name;
public Person() {}
public Person(String name) {
this.name = name;
}
public void show() {
System.out.println("装扮:"+name);
}
}
服饰类(Decorator):
package com.jxs.decoratorExample;
/**
* Created by jiangxs on 2018/5/3.
*
* 服饰类(Decorator)
*/
public class Finery extends Person {
protected Person component;
// 打扮
public void decorate(Person component) {
this.component = component;
}
@Override
public void show() {
if (component != null) {
component.show();
}
}
}
具体服饰类(ConcreteDecorator):
package com.jxs.decoratorExample;
/**
* Created by jiangxs on 2018/5/3.
*/
class TShirts extends Finery {
@Override
public void show() {
System.out.println("大T恤");
super.show();
}
}
class BigTrousers extends Finery {
@Override
public void show() {
System.out.println("垮裤");
super.show();
}
}
class Sneakers extends Finery {
@Override
public void show() {
System.out.println("破球鞋");
super.show();
}
}
class Suit extends Finery {
@Override
public void show() {
System.out.println("西装");
super.show();
}
}
class Tie extends Finery {
@Override
public void show() {
System.out.println("领带");
super.show();
}
}
class LeatherShoes extends Finery {
@Override
public void show() {
System.out.println("皮鞋");
super.show();
}
}
客户端代码:
package com.jxs.decoratorExample;
/**
* Created by jiangxs on 2018/5/3.
*/
public class Client {
public static void main(String[] args) {
Person xc = new Person("小菜");
System.out.println("第一种装扮:");
Sneakers pqx = new Sneakers();
BigTrousers dkc = new BigTrousers();
TShirts tx = new TShirts();
pqx.decorate(xc);
dkc.decorate(pqx);
tx.decorate(dkc);
tx.show();
System.out.println("\n第二种装扮");
LeatherShoes px = new LeatherShoes();
Tie ld = new Tie();
Suit xz = new Suit();
px.decorate(xc);
ld.decorate(px);
xz.decorate(ld);
xz.show();
}
}
运行结果:
第一种装扮:
大T恤
垮裤
破球鞋
装扮:小菜
第二种装扮
西装
领带
皮鞋
装扮:小菜
Process finished with exit code 0
5.装饰模式总结
装饰模式是为已有功能动态地添加更多功能的一种方式。
如果当系统需要新功能时,是向旧的类中添加新的代码,这些新的代码通常装饰了原有类的核心职责和主要行为。这种做法的问题在于:他们在主类中加入了新的字段,新的方法和新的逻辑,从而增加了主类的复杂度。而这些新加入的东西仅仅是为了满足一些只在某种特定情况下才会执行的特殊行为的需要。
而装饰模式却提供了一个非常好的解决方案,它把每个要装饰的功能放在单独的类中,并让类包装它所要装饰的对象,因此,当需要执行特殊行为时,客户代码就可以在运行时根据需要有选择地、按顺序地使用装饰功能包装对象了。
(1)装饰模式的优点:
- 把类中的装饰功能从类中搬移去除,这样可以简化原有的类。
- 有效地把类的核心职责和装饰功能区分开,而且可以去除相关类中重复的装饰逻辑。
(2)装饰模式的缺点:
- 这种比继承更加灵活机动的特性,也同时意味着更加多的复杂性。
- 装饰模式会导致设计中出现许多小类,如果过度使用,会使程序变得很复杂。
- 装饰模式是针对抽象组件(Component)类型编程。但是,如果你要针对具体组件编程时,就应该重新思考你的应用架构,以及装饰者是否合适。当然也可以改变Component接口,增加新的公开的行为,实现“半透明”的装饰者模式。在实际项目中要做出最佳选择。
(3)适用装饰者模式场合:
- 当我们需要为某个现有的对象,动态的增加一个新的功能或职责时,可以考虑使用装饰模式。
- 当某个对象的职责经常发生变化或者经常需要动态的增加职责,避免为了适应这样的变化,而增加继承子类扩展的方式,因为这种方式会造成子类膨胀的速度过快,难以控制。
注:以上代码均可在github上进行下载:https://github.com/xsongj/designPattern
参考:《大话设计模式》