设计模式----装饰模式

结构型模式

适用:当对一个类的功能进行扩展的时候,往往会往类里面 增加新的方法。但是有时在运行就需要生成一个具有新的行为的对象,当所增加的行为相对于整个类来说是比较微小时,最后可以做到不改变类文件和使用继承的情况下,动态的扩展某个对象的功能。

定义:动态给一个对象增加一些额外的职责,就增加功能来说,装饰模式比增加子类更为灵活。

举个例子:人有这个类已经具有呼吸,吃饭,走路这些功能了,现在有个会跳舞的人,那么我们会增加一个子类跳舞的人继承自人,使其拥有跳舞的方法。这就是增加子类的方式,可是有很明显的弊端,无法再对象运行时动态的添加职责,灵活性不高。演员出演古代戏和现代戏需要化妆师来化不同的状,演员对应的就是装饰模式的Component,由于主演只有一个,也就没有必要抽象出演员父类,所以decorator类可以直接从演员类继承。

具体代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
public class Actor {
    public void act(){
        System.out.println("演员开始表演");
    }
}
public class Stylist extends Actor {
    protected Actor actor;
    public void makeUp(Actor actor){
        this.actor = actor;
    }
    public void act(){
        if(null != actor){
            actor.act();
        }
    }
}
public class AncientStylist extends Stylist {
    private void showRole(){
        System.out.println("演员将要出演古装戏:");
    }
    private void makeUpForActor() {
        System.out.println("给演员穿上古装");
    }
    public void act(){
        showRole();
        makeUpForActor();
        super.act();
    }
}
public class ModernStylist extends Stylist {
    private void showRole(){
        System.out.println("演员将要出演现代戏:");
    }
    private void makeUpForActor() {
        System.out.println("给演员穿上现代服");
    }
    public void act(){
        showRole();
        makeUpForActor();
        super.act();
    }
}
public static void main(String argsp[]) {
    Actor actor = new Actor();
    ModernStylist modernStylist = new ModernStylist();
    AncientStylist ancientStylist = new AncientStylist();
    modernStylist.makeUp(actor);
    modernStylist.act();
    ancientStylist.makeUp(actor);
    modernStylist.act();
}

结构图:

基本代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
//组件抽象父类
public abstract class Component {
    public abstract void operation();
}
public class ConcreteComponent extends Component {
 
    @Override
    public void operation() {
        // TODO Auto-generated method stub
        System.out.println("basis operation");
    }
 
}
public class ConcreteDecoratorA extends Decorator {
    private String addedState;
 
    public void operation(){
        super.operation();
        addedState = "new state";
        System.out.println("this class has a "+ addedState);
    }
}
public class ConcreteDecoratorB extends Decorator {
    public void operation(){
        super.operation();
        addedBehavior();
    }
    public void addedBehavior(){
        System.out.println("now the object has a new method");
    }
}
public class Decorator extends Component {
 
    //仅供本类调用的对象
    protected Component component;
    //设置Component对象的方法,根据里氏代换原则适用子类作为参数
    public void setComponent(Component component) {
        this.component = component;
    }
    @Override
    public void operation() {
        if(null != component){
            component.operation();
        }
 
    }
 
}
public static void main(String argsp[]) {
    ConcreteComponent concreteComponent = new ConcreteComponent();
    ConcreteDecoratorA cA = new ConcreteDecoratorA();
    ConcreteDecoratorB cB = new ConcreteDecoratorB();
    cA.setComponent(concreteComponent);
    cB.setComponent(concreteComponent);
    System.out.println("after A:");
    cA.operation();
    System.out.println("after B");
    cB.operation();
}

可以看出装饰模式就是利用setComponent对需要被装饰的对象进行包装的。这样做的好处就是每个装饰对象的具体实现与如何使用这个对象彻底分离,装饰对象只要关心自己的功能就可以了。

总结:过多的使用装饰模式,会使整个程序的机构变得臃肿和混乱,如果通过装饰模式添加的功能比被添加的类本身多很多,那么就该反思以下是否该重构该类的设计了。

以下情况使用Decorator模式

1. 需要扩展一个类的功能,或给一个类添加附加职责。

2. 需要动态的给一个对象添加功能,这些功能可以再动态的撤销。

3. 需要增加由一些基本功能的排列组合而产生的非常大量的功能,从而使继承关系变的不现实。

4. 当不能采用生成子类的方法进行扩充时。一种情况是,可能有大量独立的扩展,为支持每一种组合将产生大量的子类,使得子类数目呈爆炸性增长。另一种情况可能是因为类定义被隐藏,或类定义不能用于生成子类。

优点:

1. Decorator模式与继承关系的目的都是要扩展对象的功能,但是Decorator可以提供比继承更多的灵活性。

2. 通过使用不同的具体装饰类以及这些装饰类的排列组合,设计师可以创造出很多不同行为的组合。

缺点:

1. 这种比继承更加灵活机动的特性,也同时意味着更加多的复杂性。

2. 装饰模式会导致设计中出现许多小类,如果过度使用,会使程序变得很复杂。

3. 装饰模式是针对抽象组件(Component)类型编程。但是,如果你要针对具体组件编程时,就应该重新思考你的应用架构,以及装饰者是否合适。当然也可以改变Component接口,增加新的公开的行为,实现“半透明”的装饰者模式。在实际项目中要做出最佳选择。

装饰者与适配者模式的区别:

 

1.关于新职责:适配器也可以在转换时增加新的职责,但主要目的不在此。装饰者模式主要是给被装饰者增加新职责的。

2.关于原接口:适配器模式是用新接口来调用原接口,原接口对新系统是不可见或者说不可用的。装饰者模式原封不动的使用原接口,系统对装饰的对象也通过原接口来完成使用。(增加新接口的装饰者模式可以认为是其变种--“半透明”装饰者)

3.关于其包裹的对象:适配器是知道被适配者的详细情况的(就是那个类或那个接口)。装饰者只知道其接口是什么,至于其具体类型(是基类还是其他派生类)只有在运行期间才知道。

 

posted @ 2014-12-17 22:48  silenceer  阅读(260)  评论(0编辑  收藏  举报