天天看点

装饰模式(Decorator Pattern、Wrapper Pattern,对象结构型模式)意图适用性结构参与者代码协作效果实现经典例子相关模式

意图

动态地给一个对象添加一些额外的职责。就增加功能来说,Decorator模式相比生成子类更加灵活。

对装饰和内容一视同仁。

Decorator是“进行Decorate(装饰)的主体”的意思。

适用性

当需要给一个类添加新的行为的时候,但基于开闭原则,就使用装饰模式。

在以下情况使用Decorator模式:

1. 在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责

2. 处理那些可以撤销的职责

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

结构

装饰模式(Decorator Pattern、Wrapper Pattern,对象结构型模式)意图适用性结构参与者代码协作效果实现经典例子相关模式

参与者

Component

定义一个对象接口,可以给这些对象动态增加职责。

ConcreteComponent

定义一个对象,可以给这个对象增加一些职责

Decorator

维持一个指向Component对象的指针,并定义一个与Component接口一致的接口(可以直接实现Component接口)。

ConcreteDecorator

向组件添加职责

Client

使用组合完成功能的扩展。

代码

Component

public interface Component {
    public void defaultMethod();
}
           

ConcreteComponent

public class ConcreteComponent implements Component{
    public void defaultMethod(){
        System.out.println("====ConcreteComponent===defaultMethod===");
    }
}
           

Decorator

public abstract class Decorator implements Component{
    private Component component;
    public Decorator(Component component){
        this.component = component;
    }
    public Component getComponent() {
        return component;
    }
    public void setComponent(Component component) {
        this.component = component;
    }
}
           

ConcreteDecorator

public class ConcreteDecorator1 extends Decorator{

    private int state = 0;

    public ConcreteDecorator1(Component component,int state) {
        super(component);
        this.state = state;
    }

    public void defaultMethod() {
        this.getComponent().defaultMethod();
    }

    public void add1(){
        System.out.println("====ConcreteDecorator1===add1==="+state);
    }

    public int getState() {
        return state;
    }

    public void setState(int state) {
        this.state = state;
    }
}
public class ConcreteDecorator2 extends Decorator{
    public ConcreteDecorator2(Component component) {
        super(component);
    }
    public void defaultMethod() {
        this.getComponent().defaultMethod();
    }
    public void add1(){
        System.out.println("====ConcreteDecorator2===add1===");
    }
    public void add2(){
        System.out.println("====ConcreteDecorator2===add2===");
    }
}
           

Client

public class Client {
    public static void main(String[] args) {
        Component concreteComponent = new ConcreteComponent();
        concreteComponent.defaultMethod();
        System.out.println("=========");
        ConcreteDecorator1 concreteDecorator1 = new ConcreteDecorator1(concreteComponent,1);
        concreteDecorator1.defaultMethod();
        concreteDecorator1.add1();
        System.out.println("=========");
        ConcreteDecorator2 concreteDecorator2 = new ConcreteDecorator2(concreteComponent);
        concreteDecorator2.defaultMethod();
        concreteDecorator2.add1();
        concreteDecorator2.add2();
        System.out.println("=========");
        ConcreteDecorator1 concreteDecorator3 = new ConcreteDecorator1(concreteDecorator2,1);
        concreteDecorator3.defaultMethod();
        concreteDecorator3.add1();
        System.out.println("=========");

        ConcreteDecorator2 concreteDecorator4 = new ConcreteDecorator2(concreteDecorator1);
        concreteDecorator4.defaultMethod();
        concreteDecorator4.add1();
        concreteDecorator4.add2();
    }
}
           

协作

Decorator将请求转发给它的Component对象,并有可能在转发请求前后执行一些附加的动作。

效果

比静态集成更加灵活

与对象的静态继承相比,Decorator模式提供了更加灵活的向对象添加职责的方式。可以用添加和分离的方法,用装饰在运行时刻增加或删除职责。相比之下,继承机制要求为每个添加的职责创建一个新的子类。这会产生许多新类,并且会增加系统的复杂度。此外,为一个特定的Component类提供多个不同的Decorator类,这就使得你可以对一些职责进行混合和匹配。

使用Decorator模式可以容易地重复添加一个特性。

避免在层次结构高层的类有太多的特征

Decorator模式提供了一种“即用即付”的方法来添加职责。它并不试图在一个复杂的可定制的类中支持所有可预见的特征。相反,你可以定义一个简单的类,并且用Decorator类给他逐渐地添加功能。可以从简单的部件组合出复杂的功能。这样,应用程序不必为不需要的特征付出代价。同时也更容易不依赖于Decorator所扩展(甚至是不可预知的扩展)的类而独立定义新类型的Decorator。扩展一个复杂类的时候,很可能会暴漏与添加的职责无关的细节。

Decorator与它的Component不一样

Decorator是一个透明的包装。如果我们从对象标识的观点出发,一个被装饰了的组件与这个组件是有差别的,因此使用装饰时不应该依赖于对象标识。

有许多小对象

采用Decorator模式进行系统设计往往会产生许多看上去类似的小对象,这些对象仅仅在他们相互连接的方式上有所不同,而不是他们的类或是他们的属性值有所不同。尽管对于那些了解这些系统的人来说,很容易对它们进行定制,但是很难学习这些系统,排错也很困难。

实现

使用Decorator模式时应该注意以下几点:

接口一致性

装饰对象的接口必须和它所装饰的Component的接口是一致的,因此,所有的ConcreteDecorator类必须有一个公共的父类。

省略抽象的Decorator类

当你仅需要添加一个职责时,没有必要定义抽象Decorator类。你尝尝需要处理现存的类层次结构而不是设计一个新系统,这时你可以把Decorator向Component转发请求的职责合并到ConcreteDecorator中。

保持Component类的简单性

为了保证接口的一致性,组件和装饰必须有一个公共的Component父类。因此保持这个类的简单性是很重要的:即,它应集中于定义接口而不是存储数据。对数据表示的定义应该延迟到子类中,否则Component类会变得过于复杂和庞大,因而难以大量使用。赋予Component太多的功能也使得,具体的子类有一些它们并不需要的功能的可能性大大增加。

改变对象外壳与改变对象内核

我们可以将Decorator看作一个对象的外壳,它可以改变这个对象的行为。另外一种方法是改变对象的内核(Strategy模式)。

当Component类原本就很庞大时,使用Decorator模式代价太高,Strategy模式相对更好一些。在Strategy模式中,组件将它的一些行为转发给一个独立的策略对象,我们可以替换strategy对象,从而改变或扩充组件的功能。

由于Decorator模式仅从外部改变组件,因此组件无需对它的装饰有任何了解:也就是说这些装饰对组件是透明的。

在Strategy模式中,component组件本身知道可能进行哪些扩充,因此它必须引用并维护相应的策略。

基于Strategy的方法可能需要修改component组件以适应新的扩充。另一方面,一个策略可以有自己特定的接口,而装饰的接口则必须与组件的接口一致。这意味着即使Component类很庞大,策略也可以很小。

经典例子

装饰模式(Decorator Pattern、Wrapper Pattern,对象结构型模式)意图适用性结构参与者代码协作效果实现经典例子相关模式

相关模式

Adapter Pattern

Decorator模式不同于Adapter模式,因为装饰仅改变对象的职责而不改变它的接口;而适配器讲给对象一个全新的接口。

Decorator Pattern 不改变内容的接口(API)就能建立外框(穿透作用)。

Composite Pattern

可以将装饰视为一个退化的,仅有一个组件的组合。然而,装饰仅给对象添加一些额外的职责,它的目的不在于对象聚集。

侧重通过递归组合构造类,使不同的对象、多重的对象可以“一视同仁”;而装饰模式仅仅是借递归组合来达到定义的目的

Strategy Pattern

用一个装饰你可以改变对象的外表;而Strategy模式使得你可以改变对象的内核。

Decorator Pattern 可利用更换外框或增加其他外框的方式增加新功能;Strategy Pattern:以切换预算法则的方式变换功能。

敬请期待“组合模式(Composite Pattern,对象结构型模式)”