裝飾模式
裝飾模式又名包裝模式。
裝飾模式以對客戶端透明的方式擴展對象的功能,是繼承關係的一個替代方案。
裝飾模式以對客戶透明的方式動態的給一個對象附加上更多的責任。換言之,客戶端並不會覺得對象在裝飾前和裝飾後有什麼不同。
裝飾模式可以在不創造更多子類的情況下,將對象的功能加以擴展。
裝飾模式把客戶端的調用委派到被裝飾類。裝飾模式的關鍵在於這種擴展完全是透明的。
裝飾模式使在不必改變原類文件和使用繼承的情況下,動態的擴展一個對象的功能。它是通過創建一個包裝對象,也就是裝飾來包裹真實的對象。
裝飾模式的角色:
——抽象構件角色(Component):給出一個抽象接口,以規範準備接收附加責任的對象。
——具體構件角色(Concrete Component):定義一個將要接收附加責任的類。
——裝飾角色(Decorator):持有一個構件(Component)對象的引用,並定義一個與抽象構件接口一致的接口。
——具體裝飾角色(Concrete Decorator):負責給構件對象“貼上”附加的責任。
裝飾模式的特點:
——裝飾對象和真實對象有相同的接口。這樣客戶端對象就可以以和真實對象相同的方式和裝飾對象交互。
——裝飾對象包含一個真實對象的引用(reference)
——裝飾對象接收所有來自客戶端的請求。它把這些請求轉發給真實的對象。
——裝飾對象可以在轉發這些請求以前或以後增加一些附加功能。這樣就確保了在運行時,不用修改給定對象的結構就可以在外部增加附加的功能。在面向對象的設計中,通常是通過繼承來實現對給定類的功能擴展。
裝飾模式與繼承的比較
——裝飾模式
用來擴展特定對象的功能
不需要子類
動態
運行時分配職責
防止由於子類而導致的複雜和混亂
更多的靈活性
對於一個給定的對象,同時可能有不同的裝飾對象,客戶端可以通過它的需要選擇合適的裝飾對象發送消息。
——繼承
用來擴展一類對象的功能
需要子類
靜態
編譯時分派職責
導致很多子類產生
缺乏靈活性
裝飾模式的舉例說明
抽象構件角色Component
//抽象構件角色
public interface Component {
public void doSomething();
}
具體構件角色ConcreteComponent 要實現抽象構件接口
//具體構件角色
public class ConcreteComponent implements Component {
@Override
public void doSomething() {
System.out.println("功能A");
}
}
裝飾角色(Decorator) 持有一個構件(Component)對象的引用,並定義一個與抽象構件接口一致的接口
//裝飾角色
public class Decorator implements Component {
private Component component;
public Decorator(Component component)
{
this.component=component;
}
@Override
public void doSomething() {
component.doSomething();
}
}
具體裝飾角色(Concrete Decorator):負責給構件對象“貼上”附加的責任。
//具體裝飾角色
public class ConcreteDecorator1 extends Decorator {
public ConcreteDecorator1(Component component) {
super(component);
}
@Override
public void doSomething() {
super.doSomething(); //To change body of overridden methods use File | Settings | File Templates.
this.doAnotherSomething();
}
private void doAnotherSomething()
{
System.out.println("功能B");
}
}
//具體裝飾角色
public class ConcreteDecorator2 extends Decorator {
public ConcreteDecorator2(Component component) {
super(component);
}
@Override
public void doSomething() {
super.doSomething(); //To change body of overridden methods use File | Settings | File Templates.
this.doAnotherSomething();
}
private void doAnotherSomething()
{
System.out.println("功能C");
}
}
測試類Client
public class Client {
public static void main(String[] args)
{
/*
//類比於節點流
Component component = new ConcreteComponent();
// 類比於過濾流
Component component2 = new ConcreteDecorator1(component);
//類比於過濾流
Component component3 = new ConcreteDecorator2(component2);
component3.doSomething();
*/
Component component = new ConcreteDecorator2(new ConcreteDecorator1(new ConcreteComponent()));
component.doSomething();
}
}