Decorator模式中遭遇繼承與聚合
發(fā)表時(shí)間:2024-05-18 來源:明輝站整理相關(guān)軟件相關(guān)文章人氣:
[摘要]一:背景:Decorator *Decorator 常被翻譯成"裝飾",我覺得翻譯成"油漆工"更形象點(diǎn),油漆工(decorator)是用來刷油漆的,那么被刷油漆的對(duì)象我們稱decoratee.這兩種實(shí)體在Decorator 模式中是必須的。 *Dec...
一:背景:Decorator *Decorator 常被翻譯成"裝飾",我覺得翻譯成"油漆工"更形象點(diǎn),油漆工(decorator)是用來刷油漆的,那么被刷油漆的對(duì)象我們稱decoratee.這兩種實(shí)體在Decorator 模式中是必須的。
*Decorator 定義:
動(dòng)態(tài)給一個(gè)對(duì)象添加一些額外的職責(zé),就象在墻上刷油漆.使用Decorator 模式相比用生成子類方式達(dá)到功能的擴(kuò)充顯得更為靈活。
*為什么使用Decorator?
我們通?梢允褂美^承來實(shí)現(xiàn)功能的拓展,如果這些需要拓展的功能的種類很繁多,那么勢(shì)必生成很多子類,增加系統(tǒng)的復(fù)雜性,同時(shí),使用繼承實(shí)現(xiàn)功能拓展,我們必須可預(yù)見這些拓展功能,這些功能是編譯時(shí)就確定了,是靜態(tài)的。
使用Decorator 的理由是:這些功能需要由用戶動(dòng)態(tài)決定加入的方式和時(shí)機(jī).Decorator 提供了"即插即用"的方法,在運(yùn)行期間決定何時(shí)增加何種功能。
*對(duì)于該模式,初步歸納為
1.基本功能為接口
2.Decorator參數(shù)為接口本身也為接口以便為下一個(gè)Decorator的參數(shù)
3.基本功能類實(shí)現(xiàn)接口 并作為Decorator構(gòu)造函數(shù)的參數(shù),以便在此基礎(chǔ)上添加新功能
4.額外功能由Decorator中的數(shù)據(jù)結(jié)構(gòu)處理
二:?jiǎn)栴}
這是一段Decorator設(shè)計(jì)模式的實(shí)現(xiàn)例子如下:
基本功能: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;
}
}
}
}
按如下步驟運(yùn)行出現(xiàn)明顯問題:
1:選3,"Lower Limit",
2:選3,"Read Value" 獲得的值是 6
3:選1,"Increment"(此后value值應(yīng)為 7)
4:選3,"Read Value" 獲得的值是 7(正確)
5:選2,"Decrement"(此后的value值應(yīng)為 6)
6:選3,"Read Value" 獲得的值為 7 (問題出現(xiàn)了)
考察 Upper Limit 時(shí)同樣出現(xiàn)該問題
三:追究 從輸出的追蹤語句可以看出在class LowerLimit的decrement方法的開始兩輸出語句具有明顯的指導(dǎo)意義而其中一方法是調(diào)用的來自父類的read_value()而另一個(gè)為聚合對(duì)象的read_value()。在上面步驟的第六步兩句分別輸出
Class value :7
Dec value :6
可見,有兩份value的存在。問題是兩份如何產(chǎn)生?
繼續(xù)觀察,工廠在開關(guān)語句選中case 3時(shí)調(diào)用的是
return new LowerLimit(new Counter(value));
其中新建一匿名對(duì)象為參數(shù),繼續(xù)追蹤該過程,發(fā)現(xiàn)在class Decorator 中該匿名對(duì)象被Decorator的屬性指向,而在指向之前,Decorator還把該匿名對(duì)象傳給其父類,而父類取得該對(duì)象后僅僅是取出該對(duì)象中value的拷貝,由此有兩份value存在:
1.在Decorator自身中(父類的value)
2.也在Decorator自身中(成員變量Counter的value屬性)!
問題漸漸明朗,再次觀察class LowerLimit,它僅僅實(shí)現(xiàn)了decrement()方法,也就是說,對(duì)LowerLimit調(diào)用read_value()與increment()時(shí),其全部追溯到其父類中執(zhí)行,而被作用的值value為第一類型值。對(duì)LowerLimit調(diào)用decrement()方法時(shí),該方法是用其成員變量Counter的read_value()來執(zhí)行的。此時(shí)被作用的值為第二類型值.所以會(huì)出現(xiàn)value值不同步的現(xiàn)象。
四:解決 很明顯,解決方法在于僅使用其中一份value值,當(dāng)然,Decorator本身的目的便在于避免使用繼承,所以應(yīng)當(dāng)覆蓋原有的方法,用成員變量的方法實(shí)現(xiàn)內(nèi)部實(shí)現(xiàn)。也就是將代碼中的注釋去掉.
五:小結(jié)
父類獲得了只是值的拷貝 而本身的聚合對(duì)象獲得了(參數(shù)的)全部的引用否則 如果有方法沒有覆蓋原來的 則該方法將沿用父類的 在拷貝的值(value)上操作而被覆蓋了的方法的將對(duì)本身聚合的對(duì)象中的值(value)進(jìn)行操作 于是兩value值產(chǎn)生分歧。
從Decorator模式本身的用意可知:在已有的類基礎(chǔ)上的動(dòng)態(tài)功能的添加(不是用繼承來實(shí)現(xiàn),以防太深,難以控制)所以,構(gòu)造函數(shù)的參數(shù)應(yīng)當(dāng)也必須作為"已有的類基礎(chǔ)"來對(duì)待,也就是說,自身的聚合對(duì)象必須是
該參數(shù)的引用,所有的方法也必須重造,否則將落入繼承的陷阱。