Java IO 裝飾者模式

ihze2553 8年前發布 | 11K 次閱讀 裝飾者模式 IO Java Java開發

來自: http://www.cnblogs.com/intsmaze/p/5202213.html

裝飾模式(Decorator)

裝飾模式又名 包裝(Wrapper)模式

裝飾模式以對客戶端透明的方式擴展 對象 的功能,是繼承關系的一個 替代方案。

裝飾模式通過創建一個包裝對象,也就是裝飾,來包裹真實的對象。

裝飾模式以對客戶端透明的方式 動態 地給一個對象附加上更多的責任。換言之,客戶端并不會覺得對象在裝飾前和裝飾后有什么不同。

裝飾模式可以在不創造更多子類的情況下,將對象的功能加以擴展。

裝飾模式把客戶端的調用委派到被裝飾類。裝飾模式的關鍵在于這種擴展是完全透明的。

裝飾模式的角色

抽象構件角色(Component):給出一個抽象接口,以規范準備接收附加責任的對象。

具體構件角色(Concrete Component):定義將要接收附加責任的類。

裝飾角色(Decorator):持有一個構件(Component)對象的引用,并定義一個與抽象構件接口一致的接口。

具體裝飾角色(Concrete Decorator):負責給構件對象“貼上”附加的責任。

Java IO中的裝飾模式

在IO中,具體構件角色是 節點流 ,裝飾角色是 過濾流

FilterInputStream和FilterOutputStream是裝飾角色,而其他派生自它們的類則是具體裝飾角色。

裝飾模式的特點

裝飾對象和真實對象有相同的接口。這樣客戶端對象就可以以和真實對象相同的方式和裝飾對象交互。

裝飾對象包含一個真實對象的引用(reference)。

裝飾對象接收所有來自客戶端的請求,它把這些請求轉發給真實的對象。

裝飾對象可以在轉發這些請求之前或之后附加一些功能。

這樣就確保了在運行時,不用修改給定對象的結構就可以在外部增加附加的功能。

程序實例

public interface Component{         public void

doSomething();

}

這是抽象構件角色,是一個接口。具體構件角色實現這個接口:

public class ConcreteComponent implements

Component{

@Override

public void

doSomething() {

System.out.println("功能A"

);

}

}

   </div>

</div>

裝飾角色:

public class Decorator implements

Component{

private

Component component;

public

Decorator(Component component) {

this.component =

component;

}

@Override

public

void doSomething() {

component.doSomething();

}    

}

       </div>

     </div>

   </div>

</div>

其中包含了構件角色的引用,方法調用中利用構件角色的方法。

</div>

具體裝飾角色(兩個):

public class ConcreteDecorator1 extends

Decorator{

public

ConcreteDecorator1(Component component) {

super

(component);

}

@Override

public void doSomething() {                             super

.doSomething();

this

.doAnotherThing();

}

private void

doAnotherThing() {

System.out.println("功能B");

}

}

            </div>

       </div>

     </div>

   </div>

</div>

</div>

public class ConcreteDecorator2 extends

Decorator{

public

ConcreteDecorator2(Component component) {

super

(component);

}

@Override

public void

doSomething() {

super

.doSomething();

this

.doAnotherThing();

}

private void

doAnotherThing() {

System.out.println("功能C"

);

}

}

              </div>

            </div>

          </div>

       </div>

     </div>

   </div>

使用測試:

</div>

public class Client{
         public static void main(String[] args) {
                     Component component = new ConcreteComponent();
                     Component component1 = new ConcreteDecorator1(component);
                     component1.doSomething();
                     System.out.println("-----------" );
                     Component component2 = new ConcreteDecorator2(component1);
                    component2.doSomething();
         }
}

問題引入

咖啡店的類設計:

一個飲料基類,各種飲料類繼承這個基類,并且計算各自的價錢。

飲料中需要加入各種調料,考慮在基類中加入一些布爾值變量代表是否加入各種調料,基類的cost()中的計算各種調料的價錢,子類覆蓋cost(),并且在其中調用超類的cost(),加上特定飲料的價錢,計算出子類特定飲料的價錢。

缺點:類數量爆炸、基類加入的新功能并不適用于所有的子類、調料價錢的改變、新調料的出現都會要求改變現有代碼;有的子類并不適合某些調料等情況……

設計原則

類應該對擴展開放,對修改關閉。

我們的目標是允許類容易擴展,在不修改現有代碼的情況下,就可搭配新的行為。

如能實現這樣的目標,有什么好處呢?這樣的設計具有彈性可以應對改變,可以接受新的功能來應對改變的需求。

要讓OO設計同時具備開放性和關閉性,不是一件容易的事,通常來說,沒有必要把設計的每個部分都這么設計。

遵循開放-關閉原則,通常會引入新的抽象層次,增加代碼的復雜度。

我們需要把注意力集中在設計中最有可能改變的地方,然后應用開放-關閉原則。

用裝飾者模式解決問題

解決咖啡店飲料問題的方法:

以飲料為主體,然后在運行時以調料來“裝飾”飲料。

比如,顧客想要摩卡(Mocha)和奶泡(Whip)深焙咖啡(DarkRoast):

DarkRoast繼承自Beverage,有一個cost()方法。

第一步,以DarkRoast對象開始;

第二步,顧客想要摩卡,所以建立一個Mocha裝飾者對象,并用它將DarkRoast對象包裝(wrap)起來;

第三步,顧客想要奶泡,所以建立一個Whip裝飾者對象,并用它將Mocha對象包起來;(Mocha和Whip也繼承自Beverage,有一個cost()方法);

最后,為顧客算錢,通過調用最外圈裝飾者(Whip)的cost()就可以。Whip()的cost()會先委托它裝飾的對象(Mocha)計算出價錢,然后在加上奶泡的價錢。Mocha的cost()也是類似。

裝飾者模式的特點

裝飾者和被裝飾對象 有相同的超類型

可以用一個或多個裝飾者包裝一個對象。

因為裝飾者和被裝飾者具有相同的類型,所以任何需要原始對象的場合,可以用裝飾過的對象代替。

裝飾者可以在所委托被裝飾者的行為之前與/或之后,加上自己的行為,以達到特定的目的。

對象可以在任何時候被裝飾,所以可以在運行時動態地、不限量地用你喜歡的裝飾者來裝飾對象。

裝飾者模式的定義

裝飾者模式動態地將責任附加到對象上。若要擴展功能,裝飾者提供了比繼承更有彈性的替代方案。

裝飾者模式的實現

實現類圖如下:

裝飾者和被裝飾者具有共同的超類,利用繼承達到“ 類型匹配 ”,而不是利用繼承獲得“行為”;將裝飾者和被裝飾者組合時,加入新的行為。

解決本文中飲料的具體問題時,圖中Component即為Beverage(可以是抽象類或者接口),而ConcreteComponent為各種飲 料,Decorator(抽象裝飾者)為調料的抽象類或接口,ConcreteDecoratorX則為各種具體的調料。

因為使用對象組合,可以把飲料和調料更有彈性地加以混合與匹配。

代碼外部細節:

代碼中實現的時候,通過構造函數將被裝飾者傳入裝飾者中即可,如最后的調用形式如下:

Beverage beverage = new DarkRoast();

beverage = new Mocha(beverage);

beverage = new Whip(beverage);

即完成了兩層包裝,此時再調用beverage的cost()函數即可得到總價。

java.io包內的裝飾者模式

裝飾者模式的缺點:在設計中加入大量的小類,如果過度使用,會讓程序變得復雜。

</div>

 本文由用戶 ihze2553 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!