天天看点

装饰模式(Decorator Pattern) 装饰模式的优点 装饰模式的缺点

装饰模式:

以对客户透明的方式动态地给一个对象附加上更多的责任。它是通过创建一个包装对象,也就是装饰来包裹真实的对象。若要扩展功能,装饰者比继承提供了更有弹性的替代方案。

装饰模式的类图如下:

装饰模式(Decorator Pattern) 装饰模式的优点 装饰模式的缺点

在装饰模式中的角色有:

  ●  抽象构件(Component)角色:给出一个抽象接口,以规范准备接收附加责任的对象。

  ●  具体构件(ConcreteComponent)角色:定义一个将要接收附加责任的类。

  ●  装饰(Decorator)角色:持有一个构件(Component)对象的实例,并定义一个与抽象构件接口一致的接口。

  ●  具体装饰(ConcreteDecorator)角色:负责给构件对象“贴上”附加的责任。

源代码:

抽象构建component:

public interface Animal {
    void behavior();
}      

具体构建concreteComponent:

public class Dog implements Animal {
    public void behavior() {
        System.out.println("小狗会跑");
    }
}      

装饰者decorator:

public class Sports implements Animal {
    private Animal animal;

    public Sports(Animal animal){
        this.animal = animal;
    }

    public void behavior(){
        this.animal.behavior();
    }
}      

具体状态 concreteDecorator:

public class Jump extends Sports {
    public Jump(Animal animal) {
        super(animal);
    }

    @Override
    public void behavior() {
        super.behavior();
        System.out.println("会跳");
    }
}      
public class Sleep extends Sports{
    public Sleep(Animal animal) {
        super(animal);
    }

    public void behavior(){
        super.behavior();
        System.out.println("累了会睡觉");
    }

}      
public class Thought extends Sports{
    public Thought(Animal animal) {
        super(animal);
    }

    public void think(){
        System.out.println("这是一只会思考的动物");
    }
}      

测试代码:

public class Test {
    public static void main(String[] args) {
        //透明的装饰模式
        Animal animal = new Dog();
        animal.behavior();
        System.out.println();
        animal = new Jump(animal);
        animal.behavior();
        System.out.println();
        animal = new Sleep(animal);
        animal.behavior();
        System.out.println();
        //半透明的装饰模式
        Thought thought = new Thought(new Dog());
        thought.think();
        thought.behavior();
    }
}      

输出结果:

小狗会跑

小狗会跑

会跳

小狗会跑

会跳

累了会睡觉

小狗会跑

这是一只会思考的动物

可以看到我在测试代码里面分为了2个部分:透明的状态模式,半透明的装饰模式。下面就以这2个部分来介绍一下装饰模式的使用。

我们定义了Dog类,定义了他的行为是“小狗会跑”。同时,我们又定义了一下装饰者Jump,Sleep,通过下面这个代码活动一个动物

Animal sleep = new Sleep(new Jump(new Dog()));      

这只动物的行为其实就是测试方法中输出的:

小狗会跑

会跳

累了会睡觉

这就是文字开头说的通过创建一个包装对象,也就是装饰来包裹真实的对象,动态地给一个对象附加上更多的责任。

这里动态的增加的责任就是跳和睡觉。

那么什么是透明和半透明呢?

透明的装饰模式:

理想的装饰模式开头也提到了:以对客户透明的方式动态地给一个对象附加上更多的责任。

这里的对客户透明实际上就是面向接口编程

Animal sleep= new Sleep(new Jump(new Dog()));      

还是用这个例子来说明,我们定义的是Animal,是一个接口,而不是他正在的实现Sleep类。也就是说 装饰模式对客户端的透明性要求程序不要声明一个ConcreteComponent类型的变量,而应当声明一个Component类型的变量。因此我们应该这样写

Animal dog = new Dog();
Animal jump = new Jump(new Dog());      

而不应该这样写

Dog dog = new Dog();
Jump jump = new Jump(new Dog());      

半透明的装饰模式:

然而,纯粹的装饰模式很难找到。装饰模式的用意是在不改变接口的前提下,增强所考虑的类的性能。在增强性能的时候,往往需要建立新的公开的方法。就好比我们需要的不仅仅是有行为能力的动物,还需要能思考的动物时,我们定义了一个Thought类,提供了思考的功能。那么需要使用这个think()方法的时候,就不能通过声明Animal接口来获得这个功能,而是声明Thought的引用。

//半透明的装饰模式
        Thought thought = new Thought(new Dog());
        thought.think();
        thought.behavior();      

装饰模式的优点

  (1)装饰模式与继承关系的目的都是要扩展对象的功能,但是装饰模式可以提供比继承更多的灵活性。装饰模式允许系统动态决定“贴上”一个需要的“装饰”,或者除掉一个不需要的“装饰”。继承关系则不同,继承关系是静态的,它在系统运行前就决定了。

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

装饰模式的缺点

  由于使用装饰模式,可以比使用继承关系需要较少数目的类。使用较少的类,当然使设计比较易于进行。但是,在另一方面,使用装饰模式会产生比使用继承关系更多的对象。更多的对象会使得查错变得困难,特别是这些对象看上去都很相像。

继续阅读