深入理解模板模式及实际应用
2019獨(dú)角獸企業(yè)重金招聘Python工程師標(biāo)準(zhǔn)>>>
????????原來寫了一個博客,記一次Spring環(huán)境使用模板模式。用了之后美滋滋。但是通過這幾天的壓力測試。發(fā)現(xiàn),都怪自己太年少,太懵懂,太無知。
現(xiàn)在好好梳理下模板模式的使用姿勢。
模板模式基本使用場景:
????????模板方法模式是通過父類建立框架,子類在重寫了父類部分方法之后,在調(diào)用從父類繼承的方法,產(chǎn)生不同的效果,通過修改子類,影響父類行為的結(jié)果,模板方法在一些開源框架中應(yīng)用非常多,它提供了一個抽象類,然后開源框架寫了一堆子類,如果需要擴(kuò)展功能,可以繼承此抽象類,然后覆寫protected基本方法,然后在調(diào)用一個類似TemplateMethod()的模板方法,完成擴(kuò)展開發(fā)。
模板模式優(yōu)點(diǎn):
????????模板方法模式是比較簡單的一種設(shè)計(jì)模式,但是它卻是代碼復(fù)用的一項(xiàng)基本的技術(shù),在類庫中尤其重要,它遵循“抽象類應(yīng)當(dāng)擁有盡可能多的行為,應(yīng)當(dāng)擁有盡可能少的數(shù)據(jù)”的重構(gòu)原則。作為模板的方法要定義在父類中,在方法的定義中使用到抽象方法,而只看父類的抽象方法是根本不知道怎樣處理的,實(shí)際做具體處理的是子類,在子類中實(shí)現(xiàn)具體功能,因此不同的子類執(zhí)行將會得出不同的實(shí)現(xiàn)結(jié)果,但是處理流程還是按照父類定制的方式。這就是模板方法的要義所在,制定算法骨架,讓子類具體實(shí)現(xiàn)。 其實(shí)也是抽象類的使用優(yōu)點(diǎn)。
Sping環(huán)境使用:
????????spring環(huán)境中難免的注入屬性,然后進(jìn)行邏輯處理。這時(shí)注入就是問題。直接是不能給抽象父類注入的。抽象類不能被實(shí)例化。所以就有了子類注入后為父類設(shè)置。super.name = this.name;這種反人類的注入方式。最后參考了很多方式優(yōu)化了僅在抽象父類中使用set方法注入所有公用屬性。這里不使用抽象類的構(gòu)造函數(shù)注入也是為了減少子類的重復(fù)代碼。
JDK?1.8 模板模式和接口默認(rèn)方法:
????? ? jdk1.8 很大的變化就是函數(shù)式編程,和接口默認(rèn)方法。接口默認(rèn)方法在《JAVA 8 IN ACTION》 中是對API接口維護(hù)者的重大感覺,不用因?yàn)榻涌诘母淖?#xff0c;而對實(shí)現(xiàn)類改變。然后就是默認(rèn)方法的最接口方法的組合和選擇。經(jīng)過我實(shí)際使用發(fā)現(xiàn),在注入屬性時(shí)還是有很多不便的地方。
這是接口默認(rèn)方法的方式:https://yq.aliyun.com/articles/18211
我使用了Lambda函數(shù)接口實(shí)現(xiàn)模板模式更加靈活;
傳統(tǒng)模板模式:
/*** 在線銀行*/ abstract class OnlineBanking{/*** 模板方法*/public processCustomer(int id){Customer c = Datebase.getCustomerWithID(id);makeCustomerHappy(c);}/*** 讓上帝爽*/abstract void makeCustomerHappy(Customer c ); }Lambda版本:
/*** 在線銀行*/ @Service public class OnlineBanking{/*** 模板方法*/public processCustomer(int id,Consumer<Customer> makeCustomerHappy){Customer c = Datebase.getCustomerWithID(id);makeCustomerHappy.accept(c);} }// 使用方式 public class Test{@AutowriedOnlineBanking onlineBanking;public void test{onlineBanking.processCustomer(123,(Consumer c) -> {// 做一些羞羞的事})} }至此,完畢。
以下幾個知識點(diǎn)是本次使用中反復(fù)用到的:
類加載順序:
一、過程
??Person p = new Person();
??1,JVM會去讀取指定路徑下的Person.class文件,并加載進(jìn)內(nèi)存,
??? 并會先加載Person的父類(如果有直接父類的情況下)
??2,在堆內(nèi)存中開辟空間,分配地址。
??3,并在對象空間中,對對象中的屬性進(jìn)行默認(rèn)初始化
??4,調(diào)用對應(yīng)的構(gòu)造函數(shù),進(jìn)行初始化
??5,在構(gòu)造函數(shù)中,第一行會先調(diào)用父類中的構(gòu)造函數(shù)進(jìn)行初始化。
??6,父類初始化完畢后,再對子類的屬性,進(jìn)行顯示初始化。
??7,指定構(gòu)造函數(shù)的特定初始化
??8,初始化完畢后,將堆內(nèi)存中的地址值賦給引用變量。
??即:過程為:
???子類屬性默認(rèn)初始化==》父類構(gòu)造函數(shù)初始化==》子類屬性顯示初始化!!!
二、特點(diǎn):
??在子類構(gòu)造對象時(shí),發(fā)現(xiàn),訪問子類構(gòu)造函數(shù)時(shí),父類也運(yùn)行了。
????一】具體:
??????在子類的構(gòu)造函數(shù)中第一行有一個默認(rèn)的隱式語句。 super();
??????但是,當(dāng)自己在子類構(gòu)造函數(shù)中寫了一個super的構(gòu)造語句,則就不會自動調(diào)用了。
????注意:當(dāng)父類中構(gòu)造函數(shù)為Fu(int x)時(shí),
???????子類中則必須用super(6);否則報(bào)錯!
? ??子類的實(shí)例化過程中:
?????子類中所有的構(gòu)造函數(shù)默認(rèn)都會訪問父類中的空參數(shù)構(gòu)造函數(shù)。
????三、【重點(diǎn)】為什么子類實(shí)例化的時(shí)候要訪問父類中的構(gòu)造函數(shù)?
?????1》子類繼承了父類,獲取到了父類中的內(nèi)容(屬性),所以在使用父類內(nèi)容之前
?????? 要先看父類是如何對自己的內(nèi)容進(jìn)行初始化的。
??????? 所以子類在構(gòu)造對象時(shí),就必須訪問父類中的構(gòu)造函數(shù),因此要在子類的構(gòu)造函數(shù)中加入super語句。
?????2》如果父類中沒有定義空構(gòu)造函數(shù),那么子類的構(gòu)造函數(shù)必須用super明確調(diào)用父類中對應(yīng)的構(gòu)造函數(shù)
?????3》子類構(gòu)造函數(shù)中如果使用this調(diào)用了本類構(gòu)造函數(shù)時(shí),則調(diào)用this的這個構(gòu)造函數(shù)中super便沒有了,
??????? 因?yàn)閟uper和this都只能定義在第一行。
????????但是可以保證的是,子類中肯定會有其它的構(gòu)造函數(shù)訪問父類的構(gòu)造函數(shù)。
???? 注:super語句必須要定義在子類構(gòu)造函數(shù)的第一行。因?yàn)楦割惖某跏蓟瘎幼饕韧瓿伞?br /> ???? 注:java所有的類都是Objiect的子類。
java中 抽象類構(gòu)造方法的理解
抽象類可以有構(gòu)造方法,只是不能直接創(chuàng)建抽象類的實(shí)例對象而已。
在繼承了抽象類的子類中通過super(參數(shù)列表)調(diào)用抽象類中的構(gòu)造方法
示例代碼如下:
運(yùn)行結(jié)果:
?
抽象類雖然不能自己實(shí)例化對象,但是在子類新建對象調(diào)用子類的構(gòu)造方法時(shí)會先調(diào)用抽象類的無參構(gòu)造方法,這樣一來,就可以給給抽象類的參數(shù)賦值了。
?
轉(zhuǎn)載于:https://my.oschina.net/u/3418748/blog/1617291
總結(jié)
以上是生活随笔為你收集整理的深入理解模板模式及实际应用的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 初认识ZK
- 下一篇: 通过facade(尤其是realtime