小A:“模板方法模式有什麼缺陷?”
大B:“組合優(yōu)先於繼承,而模板方法模式是少數(shù)幾個必須從非純虛類(C++的稱呼,就是java的interface)繼承來實現(xiàn)的模式之一。新手往往頗費周折才能理解其要義,因爲它的複雜性——概念複雜性和實現(xiàn)複雜性。而用IOC模式代替繼承纔是降低複雜性的更好方案。1、概念複雜性。從面向?qū)ο蠓椒ǖ谋举|(zhì)來講,父類負責抽象,子類負責具體。而模板方法恰好反過來了,父類實現(xiàn)了大部分功能,而子類實現(xiàn)少數(shù)純虛方法,然後由父類的方法調(diào)用。違反了面向?qū)ο蟮囊话阈运季S的原因是這個模式的初衷並不是抽象,而是最大限度的重用。2、實現(xiàn)複雜性。這種重用方式的代價就是每個子類身上都揹負了父類強加給它的包袱。”
舉個例子:
publicabstractclassApplicationContext{
protectedStringpath;
publicabstractInputStreamgetStream();
publicvoidbuild(){
getStream();
}
publicApplicationContext(Stringpath){
this.path=path;
}
}
publicclassClassPathContextextendsApplicationContext{
publicClassPathContext(Stringpath){
//super(path)執(zhí)行之前絕對不能使用path變量,因爲父類還沒有初始化。
super(path);//爲了能夠執(zhí)行父類構(gòu)建器,強加給子類的代碼。
}
publicInputStreamgetStream(){……}
}
調(diào)用代碼:
ApplicationContextcontext=newClassPathContext(“path”);
context.build();
大B:“這裡父類帶給子類的負擔有兩點:1、父類的非默認構(gòu)建器子類必須重寫。2、子類在構(gòu)建器裡使用父類的成員變量時要注意順序。由此可見,這個模式在提高重用性的同時也增加了複雜性:1、子類的編寫者必須瞭解父類的實現(xiàn)。2、父類的改動很容易波及到子類。用IOC組合方式進行就漂亮得多,把子類要實現(xiàn)的方法用interface來描述。這時兩個父子關(guān)係的類就轉(zhuǎn)變成調(diào)用與被調(diào)用的關(guān)係,之間通過interface形成契約。”
publicclassApplicationContext{
Readerreader;
publicvoidsetReader(Readerreader){this.reader=reader;}
publicvoidbuild(){
reader.getStream(path);
}
}
publicinterfaceReader{
publicInputStreamgetStream(Stringpath);
}
調(diào)用代碼:
ApplicationContextcontext=newApplicationContext(“path”);
context.setReader(newReaderImpl());
context.build();
大B:“這兩種實現(xiàn)最大的區(qū)別是ClassPathContext和ApplicationContext是緊耦合的。而ReaderImpl和ApplicaitonContext是正交的。其次就是IOC方式的實現(xiàn)代碼要麻煩,這是java嚴謹?shù)恼Z言機制決定的,如果用C#的DelegateMethod來實現(xiàn)要簡潔許多。”