1、装饰模式(decorator):动态的给一个对象添加一些额外的职责,就增加功能来说,装饰模式比生成子类更灵活。
2、装饰模式结构图:
Component是定义一个接口,可以给这些对象动态的添加职责。ConcreteComponent是定义了一个具体对象,也可以给这个对象添加一些职责。Decorator,装饰抽象类,继承了Component,从外类来扩展Component类的功能,但对于Component来说,无需知道Decorator的存在。至于ConcreteDecorator就是具体的装饰对象,起到给Component添加职责的功能。
3、基本代码实现:
Component类:
public abstract class Component {
public abstract void Operation();
}
ConcreComponent类:
public class ConcreComponent extends Component {
@Override
public void Operation() {
System.out.println("具体对象的操作");
}
}
Decorator类:
public class Decorator extends Component {
protected Component component;
// 设置Component
public void setComponent(Component component) {
this.component = component;
}
// 重写Operation(),实际执行Component的Operation
@Override
public void Operation() {
// TODO Auto-generated method stub
if (component != null) {
component.Operation();
}
}
}
ConcreteDecoratorA类:
public class ConcreteDecoratorA extends Decorator{
private String addedState="";
@Override
public void Operation() {
// TODO Auto-generated method stub
//首先运行原Component的Operation(),
super.Operation();
//再执行本类的功能,如AddedState,相当于对原Component进行了装饰
addedState="new state";
System.out.println("具体装饰对象的A的操作");
}
}
ConcreteDecoratorB类:
public class ConcreteDecoratorB extends Decorator{
@Override
public void Operation() {
// TODO Auto-generated method stub
//首先运行原Component的Operation(),
super.Operation();
//再执行本类的功能,相当于对原Component进行了装饰
addBehavior();
System.out.println("具体装饰对象的B的操作");
}
//本类独有的方法,区别于A
private void addBehavior() {
}
}
客户端类:
public class doDecorator {
public static void main(String[] args) {
ConcreComponent cc=new ConcreComponent();
ConcreteDecoratorA dca=new ConcreteDecoratorA();
ConcreteDecoratorB dcb=new ConcreteDecoratorB();
/*
* 装饰的方法:首先用ConcreteComponent实例化对象cc,
* 然后用ConcreteDecoratorA的实例化对象包装cc,
* 再用ConcreteDecoratorA的实例化对象包装dca,
* 最终执行dcb的Operation
*/
dca.setComponent(cc);
dcb.setComponent(dca);
dcb.Operation();
}
}
3.1、装饰模式是利用setComponent来对对象进行包装,这样每个装饰对象的实现就和如何使用这个对象分开了,每个装饰对象只关心自己的功能,不用关心自己如何被添加到对象链中。
3.2、如果只有一个ConcreteComponent类而没有抽象的Component类,那么Decorator类可以是ConcreteComponent的一个子类。同样的道理,如果只有ConcreteDecorator类,那么就没有必要建立一个单独的Decorator类,把ConcreteDecorator和Decorator合并成一个类。
4、书上的穿衣例子
Person 类:
public class Person {
private String name="";
public Person(String name) {
this.name=name;
}
public Person() {
// TODO Auto-generated constructor stub
}
public void show() {
System.out.println("装扮的"+name);
}
}
服饰类:
public class Finery extends Person {
protected Person person=null;
public void decorator(Person person) {
this.person=person;
}
@Override
public void show() {
if(person!=null) {
person.show();
}
}
}
具体服饰类:
public class Thirts extends Finery {
@Override
public void show() {
// TODO Auto-generated method stub
System.out.println("大T恤");
super.show();
}
}
public class BigTrouser extends Finery {
@Override
public void show() {
// TODO Auto-generated method stub
System.out.println("大垮裤");
super.show();
}
}
public class Sneaker extends Finery {
@Override
public void show() {
// TODO Auto-generated method stub
System.out.println("运动鞋");
super.show();
}
}
public class Suit extends Finery {
@Override
public void show() {
// TODO Auto-generated method stub
System.out.println("西装");
super.show();
}
}
public class Blouse extends Finery {
@Override
public void show() {
// TODO Auto-generated method stub
System.out.println("衬衫");
super.show();
}
}
public class PiXie extends Finery {
@Override
public void show() {
// TODO Auto-generated method stub
System.out.println("皮鞋");
super.show();
}
}
客户端:
public class Do {
public static void main(String[] args) {
Person ps=new Person("小菜");
System.out.println("第一种装扮");
Sneaker s=new Sneaker();
BigTrouser bt=new BigTrouser();
Thirts ts=new Thirts();
s.decorator(ps);
bt.decorator(s);
ts.decorator(bt);
ts.show();
System.out.println("第二种装扮");
PiXie px=new PiXie();
Blouse bs=new Blouse();
Suit st=new Suit();
px.decorator(ps);
bs.decorator(px);
st.decorator(bs);
st.show();
}
}
5、总结
5.1、装饰模式是为已有功能动态的添加更多功能的一种方式。
5.2、当系统需要新功能的时候,是向旧类中添加新代码。这些新代码通常装饰了原有类的核心职责或主要行为,在主类中加入了新的字段、新的方法、新的逻辑,从而增加了主类的复杂度,而这些新加入的东西仅仅是为了满足一些只在特定情况下才会被执行的特殊行为。装饰模式提供了一个很好的解决方案,他把每个装饰的功能放在单独的类中,并让这个类包装他所要装饰的对象,因为当执行特殊行为时,客户代码就可以在运行时根据需要有选择的、按顺序的使用装饰功能包装对象了。
5.3、装饰功能的优点:把类的装饰功能从类中除去,这样可以简化原有的类。有效的把核心职责和装饰功能区分开了,而且可以去除相关类中重复的装饰逻辑。