一:背景:Decorator
*Decorator 常被翻譯成"裝飾",我覺得翻譯成"油漆工"更形象點,油漆工(decorator)是用來刷油漆的,那么被刷油漆的對象我們稱decoratee.這兩種實體在Decorator 模式中是必須的。
*Decorator 定義:
動態給一個對象添加一些額外的職責,就象在墻上刷油漆.使用Decorator 模式相比用生成子類方式達到功能的擴充顯得更為靈活。
*為什么使用Decorator?
我們通常可以使用繼承來實現功能的拓展,如果這些需要拓展的功能的種類很繁多,那么勢必生成很多子類,增加系統的復雜性,同時,使用繼承實現功能拓展,我們必須可預見這些拓展功能,這些功能是編譯時就確定了,是靜態的。
使用Decorator 的理由是:這些功能需要由用戶動態決定加入的方式和時機.Decorator 提供了"即插即用"的方法,在運行期間決定何時增加何種功能。
*對于該模式,初步歸納為
1.基本功能為接口
2.Decorator參數為接口本身也為接口以便為下一個Decorator的參數
3.基本功能類實現接口 并作為Decorator構造函數的參數,以便在此基礎上添加新功能
4.額外功能由Decorator中的數據結構處理 二:問題
這是一段Decorator設計模式的實現例子如下:
基本功能:Counter類 需要添加的功能
1:上限控制
2:下限控制
import java.io.*; class Counter{ private int value; public Counter(int v){ System.out.println("init me here in The Counter with value!"); value=v; }
public Counter(Counter cc){ System.out.println("init me here in The Counter with class!"); value=cc.value; }
public int read_value(){ System.out.println("read me here The value is:"+value); System.out.println("read me here in The Counter!");
return value; }
public void increment(){ System.out.println("increment me here in The Counter !"); value++; }
public void decrement(){ System.out.println("decrement me here in The Counter !"); value--; } }
class Decorator extends Counter { Counter counter; public Decorator(Counter c) { super(c); System.out.println("init me here with class Decorator!"); } }
class UpperLimit extends Decorator//上限控制 { public UpperLimit(Counter c) { super(c); counter=c; System.out.println("init me here with class UpperLimit!"); } public void increment() { if(counter.read_value()>20) { System.out.println("Too High"); } else { System.out.println("increment me here with class UpperLimit!"); counter.increment(); } } /*public void decrement() { counter.decrement(); } public int read_value() { return counter.read_value(); }*/
}
class LowerLimit extends Decorator//下限控制 { public LowerLimit(Counter c) { super(c); counter=c; System.out.println("init me here in The Counter with class LowerLimit!"); } public void decrement() { System.out.println("Class value :"+read_value()); System.out.println("Dec value :"+counter.read_value()); if(counter.read_value()<=0) { System.out.println(counter.read_value()); System.out.println("Too Low"); } else { System.out.println("decrement me here in The Counter with class LowerLimit!"); counter.decrement(); } } /*public void increment() { counter.increment(); } public int read_value() { return counter.read_value(); }*/ }
class CounterFactory { public static Counter createCounter(int value,int op) { switch(op) { case 1: { return new Counter(value); } case 2: { return new UpperLimit(new Counter(value)); } case 3: { return new LowerLimit(new Counter(value)); } default: { return new UpperLimit(new LowerLimit(new Counter(value))); } } }
} class Console { private static BufferedReader read=new BufferedReader(new InputStreamReader(System.in));
public static int readInt(String index){ System.out.println(index); try{ return Integer.parseInt(read.readLine()); } catch(Exception e){ return 0; } } }
public class Q1s{ public static void main(String[] args){ System.out.println("Counter Type:"); System.out.println("1: Normal"); System.out.println("2: Upper Limit"); System.out.println("3: Lower Limit"); System.out.println("4: Upper & Lower Limit"); int option=Console.readInt("Enter Choice:"); Counter c = CounterFactory.createCounter(6,option); int choice=1; while(choice!=4){ System.out.println("1: Increment"); System.out.println("2: Decrement"); System.out.println("3: Read Value"); System.out.println("4: Exit"); choice=Console.readInt("Enter Choice:"); switch(choice){ case 1: c.increment(); break; case 2: c.decrement(); break; case 3: int v=c.read_value(); System.out.println("Value="+v);break; } } } }
按如下步驟運行出現明顯問題:
1:選3,"Lower Limit",
2:選3,"Read Value" 獲得的值是 6 3:選1,"Increment"(此后value值應為 7)
4:選3,"Read Value" 獲得的值是 7(正確)
5:選2,"Decrement"(此后的value值應為 6)
6:選3,"Read Value" 獲得的值為 7 (問題出現了)
考察 Upper Limit 時同樣出現該問題
三:追究
從輸出的追蹤語句可以看出在class LowerLimit的decrement方法的開始兩輸出語句具有明顯的指導意義而其中一方法是調用的來自父類的read_value()而另一個為聚合對象的read_value()。在上面步驟的第六步兩句分別輸出
Class value :7 Dec value :6
可見,有兩份value的存在。問題是兩份如何產生?
繼續觀察,工廠在開關語句選中case 3時調用的是
return new LowerLimit(new Counter(value));
其中新建一匿名對象為參數,繼續追蹤該過程,發現在class Decorator 中該匿名對象被Decorator的屬性指向,而在指向之前,Decorator還把該匿名對象傳給其父類,而父類取得該對象后僅僅是取出該對象中value的拷貝,由此有兩份value存在:
1.在Decorator自身中(父類的value)
2.也在Decorator自身中(成員變量Counter的value屬性)!
問題漸漸明朗,再次觀察class LowerLimit,它僅僅實現了decrement()方法,也就是說,對LowerLimit調用read_value()與increment()時,其全部追溯到其父類中執行,而被作用的值value為第一類型值。對LowerLimit調用decrement()方法時,該方法是用其成員變量Counter的read_value()來執行的。此時被作用的值為第二類型值.所以會出現value值不同步的現象。
四:解決
很明顯,解決方法在于僅使用其中一份value值,當然,Decorator本身的目的便在于避免使用繼承,所以應當覆蓋原有的方法,用成員變量的方法實現內部實現。也就是將代碼中的注釋去掉.
五:小結
父類獲得了只是值的拷貝 而本身的聚合對象獲得了(參數的)全部的引用否則 如果有方法沒有覆蓋原來的 則該方法將沿用父類的 在拷貝的值(value)上操作而被覆蓋了的方法的將對本身聚合的對象中的值(value)進行操作 于是兩value值產生分歧。
從Decorator模式本身的用意可知:在已有的類基礎上的動態功能的添加(不是用繼承來實現,以防太深,難以控制)所以,構造函數的參數應當也必須作為"已有的類基礎"來對待,也就是說,自身的聚合對象必須是 該參數的引用,所有的方法也必須重造,否則將落入繼承的陷阱。
|