1. 程式人生 > >設計模式:裝飾模式(Decorator )

設計模式:裝飾模式(Decorator )

定義與結構

裝飾模式(Decorator)也叫包裝器模式(Wrapper)。GOF 在《設計模式》一書中給出的定義為:動態地給一個物件新增一些額外的職責。就增加功能來說,Decorator 模式相比生成子類更為靈活。

讓我們來理解一下這句話。我們來設計“門”這個類。假設你根據需求為“門”類作了如下
定義:
這裡寫圖片描述
現在,在系統的一個地方需要一個能夠報警的Door,你來怎麼做呢?你或許寫一個Door的子類AlarmDoor,在裡面新增一個子類獨有的方法alarm()。嗯,那在使用警報門的地方你必須讓客戶知道使用的是警報門,不然無法使用這個獨有的方法。而且,這個還違反了Liskov 替換原則。

也許你要說,那就把這個方法新增到Door 裡面,這樣不就統一了?但是這樣所有的門都必須有警報,至少是個“啞巴”警報。而當你的系統僅僅在一兩個地方使用了警報門,這明顯是不合理的——雖然可以使用預設介面卡來彌補一下。

這時候,你可以考慮採用裝飾模式來給門動態的新增些額外的功能。
下面我們來看看裝飾模式的組成,不要急著去解決上面的問題,到了下面自然就明白了!
1) 抽象構件角色(Component):定義一個抽象介面,以規範準備接收附加責任的物件。
2) 具體構件角色(Concrete Component):這是被裝飾者,定義一個將要被裝飾增加功能的類。
3) 裝飾角色(Decorator):

持有一個構件物件的例項,並定義了抽象構件定義的介面。
4) 具體裝飾角色(Concrete Decorator):負責給構件新增增加的功能。
看下裝飾模式的類圖:
這裡寫圖片描述

圖中 ConcreteComponent 可能繼承自其它的體系,而為了實現裝飾模式,他還要實現Component 介面。整個裝飾模式的結構是按照組合模式來實現的——兩者都有類似的結構圖,都基於遞迴組合來組織可變數目的物件。但是兩者的目的是截然不同的,組合(Composite)模式側重通過遞迴組合構造類,使不同的物件、多重的物件可以“一視同仁”;而裝飾(Decorator)模式僅僅是借遞迴組合來達到定義中的目的。

裝飾模式的實現

//抽象構件角色--Component
public interface Shape {
    void draw();
}
//具體構件角色--Concrete ComponentA
public class Circle implements Shape {

    @Override
    public void draw() {
        // TODO Auto-generated method stub
        System.out.println("Shape: Circle");
    }

}
//具體構件角色--Concrete ComponentB
public class Rectangle implements Shape {

    @Override
    public void draw() {
        // TODO Auto-generated method stub
        System.out.println("Shape: Rectangle");
    }

}
//裝飾角色--Decorator
public abstract class ShapeDecorator implements Shape{
    protected Shape decoratedShape;

    public ShapeDecorator(Shape decoratedShape) {
        this.decoratedShape = decoratedShape;
    }

    public void draw() {
        decoratedShape.draw();
    }
}
//具體裝飾角色--Concrete Decorator
public class RedShapeDecorator extends ShapeDecorator {

    public RedShapeDecorator(Shape decoratedShape) {
        super(decoratedShape);
        // TODO Auto-generated constructor stub
    }

    @Override
    public void draw() {
        decoratedShape.draw();
        setRedBorder(decoratedShape);
    }

    private void setRedBorder(Shape decoratedShape) {
        System.out.println("Border Color: Red");
    }

}

//客戶端
public class DecoratorPatternDemo {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Shape circle = new Circle();

        Shape redCircle = new RedShapeDecorator(new Circle());

        Shape redRectangle = new RedShapeDecorator(new Rectangle());
        System.out.println("Circle with normal border");
        circle.draw();

        System.out.println("\nCircle of red border");
        redCircle.draw();

        System.out.println("\nRectangle of red border");
        redRectangle.draw();
    }

}

驗證輸出

Circle with normal border
Shape: Circle

Circle of red border
Shape: Circle
Border Color: Red

Rectangle of red border
Shape: Rectangle
Border Color: Red