這兩天本來是自在學習java collection Framework的Fail Fast底層機制,看到核心的部分時,突然意識到設計模式的問題,上大學到現在我還沒有真正理解過設計模式的概念,於是用了大半天好好的學習了一下裝飾器模式,回頭再看jdk的源碼,舒服多了,的確驗證了那句話,設計模式非學不可啊,可以說自己是個十足的菜鳥,連基本的java接口機制和繼承都忘得差不多了,這一天全拾起來了~
首先解釋一下忘記接口的同學難點,接口其實就是java的抽象機制,不提供方法的具體實現,但是可以有多個類來實現這個接口,一個類也可以實現多個接口,接口帶來的好處是創建實例時,用戶不必關注具體的實現,比如我例子中的DecoratorPattern.java文件中 ,創建實現Basket接口的一個實例時,返回值是接口,下面再使用show方法時,我們就不必去關注誰實現了。接口作爲返回值的一個經典的應用是使用ArrayList時,他的iterator方法會返回一個Iterator接口。這樣開發者使用it.next方法,再不用去研究每一種list是怎麼實現查詢了。
下面解釋裝飾器模式是如何引起的,深入淺出模式設計的例子很好,就是喝咖啡,有個調料的類,你可以加糖、冰、牛奶等等好多原料,那麼生成調配方案時,可以通過繼承來實現,但是大家也都知道排列組合,繼承的類系統龐大可想而知了。
這就誕生了裝飾器模式,他的原則是,保持原有的接口,併爲原來的動態的添加新的功能。
下面是維基百科的解釋:相信大家都可以看懂
“通過使用修飾模式,可以在運行時擴充一個類的功能。原理是:增加一個修飾類包裹原來的類,包裹的方式一般是通過在將原來的對象作爲修飾類的構造函數的參數。裝飾類實現新的功能,但是,在不需要用到新功能的地方,它可以直接調用原來的類中的方法。修飾類必須和原來的類有相同的接口。
修飾模式是類繼承的另外一種選擇。類繼承在編譯時候增加行爲,而裝飾模式是在運行時增加行爲。
當有幾個相互獨立的功能需要擴充時,這個區別就變得很重要。在有些面向對象的編程語言中,類不能在運行時被創建,通常在設計的時候也不能預測到有哪幾種功能組合。這就意味着要爲每一種組合創建一個新類。相反,修飾模式是面向運行時候的對象實例的,這樣就可以在運行時根據需要進行組合。一個修飾模式的示例是JAVA裏的Java I/O Streams的實現”
//補充一下,還有個經典的例子是java Collection framework也就是我們經常使用的ArrayList的底層實現機制,也是利用了裝飾器模式。
再引用網上的一個設計圖,很清晰了,我在代碼中的實現,並沒有實現裝飾器基類,而是直接去裝飾了。
下面介紹我這個演示的demo,假設我們有一個水果籃子,釐米可以裝蘋果,香蕉、或者橘子。這是可以典型的應用裝飾器模式,比如我們用三個修飾器來修飾水果籃子裏面裝的內容。假設我們使用繼承的話,那麼要想獲得所有情況,根據排列組合那麼就有8種可能,需要有7個子類(空籃子就是本身,不需繼承了)。裝飾器模式就簡單多了
第一個是Basket接口
package uni.pattern.decorator;
/*
* 創建一個對象的抽象也就是接口
*/
public interface Basket {
public void show();
}
下面是被裝飾的對象,也就是對接口的一個實現,注意可以有多個實現
package uni.pattern.decorator;
/**
*身份:被裝飾的對象
*一個對接口的實現,這個對象表示要我們將來要修飾的籃子裏裝內容,如果想修飾籃子的造型,還可以創建其他類實現Basket的接口,比如Shape
* 不理解的話可以查看java語言的接口抽象機制
*/
public class Original implements Basket{
public void show(){
System.out.println("The original Basket contains");
}
}
接下來是三個裝飾器的實現
package uni.pattern.decorator;
/**
*身份:裝飾器
*爲原來的類添加新的功能
*/
public class AppleDecorator implements Basket{
private Basket basket;
public AppleDecorator( Basket basket){
super();
this.basket = basket;
}
public void show(){
basket.show();
System.out.println("An Apple");
}
}
package uni.pattern.decorator;
/**
*身份:裝飾器
*/
public class BananaDecorator implements Basket{
private Basket basket;
public BananaDecorator(Basket basket){
super();
this.basket = basket;
}
public void show(){
basket.show();
System.out.println("A Banana");
}
}
package uni.pattern.decorator;
/**
*身份:裝飾器
*/
public class OrangeDecorator implements Basket{
private Basket basket;
public OrangeDecorator(Basket basket){
super();
this.basket = basket;
}
public void show(){
basket.show();
System.out.println("An Oranage");
}
}
最後就是實現的效果,我們三個修飾器全部用到,裝滿了籃子,當然也可以只裝一個蘋果或香蕉
/*
* 設計模式:裝飾器模式
* java 簡單的演示
*/
package decoratorpattern;
import uni.pattern.decorator.Original;
import uni.pattern.decorator.*;
/**
*
* @author octobershiner
* 2011 7 25
* SE.HIT
*/
public class DecoratorPattern {
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
// TODO code application logic here
Basket basket = new Original();
//一個裝飾的過程
Basket myBasket =new AppleDecorator(new BananaDecorator(new OrangeDecorator(basket)));
myBasket.show();
}
}
演示的結果:
run:
The original Basket contains
An Oranage
A Banana
an Apple
成功生成(總時間:0 秒)