一、依賴注入(DI) 控制反轉(zhuǎn)(IOC)



先看上面三張圖使用的公共組件ToggleBar,這個(gè)組件要求左按鈕和右按鈕點(diǎn)擊的時(shí)候,顯示的內(nèi)容會(huì)向左或向右緩動(dòng),隱藏掉一部分,并顯示之前遮住的一部分。如圖所示,不同的應(yīng)用場(chǎng)景,每一個(gè)小格子內(nèi)容是不同的,有的是一個(gè)按鈕,有的是一個(gè)物品圖標(biāo),有的復(fù)雜些,還有文本,我們簡(jiǎn)稱為renderA,renderB,renderC。這些變化的部分,作為ToggleBar的設(shè)計(jì)者,是不可預(yù)知的,可知的只有點(diǎn)擊左右按鈕,它們會(huì)排成一行做緩動(dòng)。那么,我們應(yīng)該怎么設(shè)計(jì)才能方便使用者呢?
毫無疑問,ToggleBar中必須有一個(gè)對(duì)象保存著這些變化的內(nèi)容用來展示,就叫render吧。它的類型可以是renderA,renderB,renderC的基類,當(dāng)然是一個(gè)接口更方便,把它們共有的邏輯再抽象到基類里。這樣ToggleBar就要求使用它的時(shí)候,必須指明一個(gè)render接口的對(duì)象,否則它不知道怎么去顯示。
第二個(gè)問題就是怎么把這個(gè)Render傳進(jìn)去,最好是在構(gòu)造方法里要求傳入,因?yàn)闃?gòu)造方法里需要執(zhí)行UI初始化。也可以使用setRender方法重置。
總結(jié):ToggleBar依賴render才能正常工作,但render的構(gòu)造卻不受它控制,它把控制權(quán)交給了具體的使用者,這就是控制反轉(zhuǎn)。render通過構(gòu)造方法傳入,這個(gè)就叫依賴注入。
以下參考輕松理解 Java開發(fā)中的依賴注入(DI)和控制反轉(zhuǎn)(IOC)
對(duì)比以下的兩個(gè)簡(jiǎn)單程序:
簡(jiǎn)單java程序
<pre>
package demo;
public class Activity {
public Activity(){
this.onCreate();
}
public void onCreate(){
System.out.println("onCreate called");
}
public void sayHi(){
System.out.println("Hello world!");
}
public static void main(String[] args) {
Activity a = new Activity();
a.sayHi();
}
}
</pre>
簡(jiǎn)單Android程序
<pre>
package demo;
import android.app.Activity;
import android.os.Bundle;
import android.widget.TextView;
public class MainActivity extends Activity
{
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
TextView tv = new TextView(this);
tv.append("Hello ");
tv.append("world!");
setContentView(tv);
}
}
</pre>
這兩個(gè)程序最大的區(qū)別就是,前者程序的運(yùn)行完全由開發(fā)控制,后者程序的運(yùn)行由Android框架控制.兩個(gè)程序都有個(gè)onCreate方法.前者程序中,如果開發(fā)者覺得onCreate 名稱不合適,想改為Init,沒問題,直接就可以改, 相比下,后者的onCreate 名稱就不能修改.因?yàn)?后者使用了框架,享受框架帶來福利的同時(shí),就要遵循框架的規(guī)則.
這就是控制反轉(zhuǎn).可以說, 控制反轉(zhuǎn)是所有框架最基本的特征.也是框架和普通類庫最大的不同點(diǎn).
很多Android開發(fā)工程師在享用控制反轉(zhuǎn)帶來的便利,去不知什么是控制反轉(zhuǎn).就有點(diǎn)像深海里的魚不知到什么是海水一樣.
通過框架可以把許多共用的邏輯放到框架里,讓用戶專注自己程序的邏輯.這也是為什么現(xiàn)在,無論手機(jī)開發(fā),網(wǎng)頁開發(fā),還是桌面程序, 也不管是Java,PHP,還是Python框架無處不在.
二、反射
通過字符串獲取類,動(dòng)態(tài)生成對(duì)象??梢允褂肵ML文件來組織這些字符串。反射主要是升級(jí)了工廠模式。
參考
Java反射入門
Java基礎(chǔ)與提高干貨系列——Java反射機(jī)制
以下參考Java反射機(jī)制的適用場(chǎng)景及其利與弊
- Java的反射機(jī)制在做基礎(chǔ)框架的時(shí)候非常有用,有一句話這么說來著:反射機(jī)制是很多Java框架的基石。而一般應(yīng)用層面很少用,不過這種東西,現(xiàn)在很多開源框架基本都已經(jīng)給你封裝好了,自己基本用不著寫。典型的除了hibernate之外,還有spring也用到很多反射機(jī)制。經(jīng)典的就是在xml文件或者properties里面寫好了配置,然后在Java類里面解析xml或properties里面的內(nèi)容,得到一個(gè)字符串,然后用反射機(jī)制,根據(jù)這個(gè)字符串獲得某個(gè)類的Class實(shí)例,這樣就可以動(dòng)態(tài)配置一些東西,不用每一次都要在代碼里面去new或者做其他的事情,以后要改的話直接改配置文件,代碼維護(hù)起來就很方便了,同時(shí)有時(shí)候要適應(yīng)某些需求,Java類里面不一定能直接調(diào)用另外的方法,這時(shí)候也可以通過反射機(jī)制來實(shí)現(xiàn)。
總的來說,自己寫的很少,具體什么時(shí)候要用那要看需求,反射機(jī)制無非就是根據(jù)一個(gè)String來得到你要的實(shí)體對(duì)象,然后調(diào)用它原來的東西。但是如果是要自己寫框架的話,那就會(huì)用得比較多了。 - 當(dāng)你做一個(gè)軟件可以安裝插件的功能,你連插件的類型名稱都不知道,你怎么實(shí)例化這個(gè)對(duì)象呢?因?yàn)槌绦蚴侵С植寮模ǖ谌降模?,在開發(fā)的時(shí)候并不知道 。所以無法在代碼中 New出來 ,但反射可以,通過反射,動(dòng)態(tài)加載程序集,然后讀出類,檢查標(biāo)記之后再實(shí)例化對(duì)象,就可以獲得正確的類實(shí)例。
- 在編碼階段不知道那個(gè)類名,要在運(yùn)行期從配置文件讀取類名, 這時(shí)候就沒有辦法硬編碼new ClassName(),而必須用到反射才能創(chuàng)建這個(gè)對(duì)象.反射的目的就是為了擴(kuò)展未知的應(yīng)用。比如你寫了一個(gè)程序,這個(gè)程序定義了一些接口,只要實(shí)現(xiàn)了這些接口的dll都可以作為插件來插入到這個(gè)程序中。那么怎么實(shí)現(xiàn)呢?就可以通過反射來實(shí)現(xiàn)。就是把dll加載進(jìn)內(nèi)存,然后通過反射的方式來調(diào)用dll中的方法。很多工廠模式就是使用的反射。
三、AOP
參考JavaWeb過濾器.監(jiān)聽器.攔截器-原理&區(qū)別-個(gè)人總結(jié)
面向切面編程(AOP是Aspect Oriented Program的首字母縮寫) ,我們知道,面向?qū)ο蟮奶攸c(diǎn)是繼承、多態(tài)和封裝。而封裝就要求將功能分散到不同的對(duì)象中去,這在軟件設(shè)計(jì)中往往稱為職責(zé)分配。實(shí)際上也就是說,讓不同的類設(shè)計(jì)不同的方法。這樣代碼就分散到一個(gè)個(gè)的類中去了。這樣做的好處是降低了代碼的復(fù)雜程度,使類可重用。但是人們也發(fā)現(xiàn),在分散代碼的同時(shí),也增加了代碼的重復(fù)性。什么意思呢?比如說,我們?cè)趦蓚€(gè)類中,可能都需要在每個(gè)方法中做日志。按面向?qū)ο蟮脑O(shè)計(jì)方法,我們就必須在兩個(gè)類的方法中都加入日志的內(nèi)容。也許他們是完全相同的,但就是因?yàn)槊嫦驅(qū)ο蟮脑O(shè)計(jì)讓類與類之間無法聯(lián)系,而不能將這些重復(fù)的代碼統(tǒng)一起來。也許有人會(huì)說,那好辦啊,我們可以將這段代碼寫在一個(gè)獨(dú)立的類獨(dú)立的方法里,然后再在這兩個(gè)類中調(diào)用。但是,這樣一來,這兩個(gè)類跟我們上面提到的獨(dú)立的類就有耦合了,它的改變會(huì)影響這兩個(gè)類。那么,有沒有什么辦法,能讓我們?cè)谛枰臅r(shí)候,隨意地加入代碼呢?**這種在運(yùn)行時(shí),動(dòng)態(tài)地將代碼切入到類的指定方法、指定位置上的編程思想就是面向切面的編程。 **一般而言,我們管切入到指定類指定方法的代碼片段稱為切面,而切入到哪些類、哪些方法則叫切入點(diǎn)。有了AOP,我們就可以把幾個(gè)類共有的代碼,抽取到一個(gè)切片中,等到需要時(shí)再切入對(duì)象中去,從而改變其原有的行為。這樣看來,AOP其實(shí)只是OOP的補(bǔ)充而已。OOP從橫向上區(qū)分出一個(gè)個(gè)的類來,而AOP則從縱向上向?qū)ο笾屑尤胩囟ǖ拇a。有了AOP,OOP變得立體了。如果加上時(shí)間維度,AOP使OOP由原來的二維變?yōu)槿S了,由平面變成立體了。從技術(shù)上來說,AOP基本上是通過代理機(jī)制實(shí)現(xiàn)的。AOP在編程歷史上可以說是里程碑式的,對(duì)OOP編程是一種十分有益的補(bǔ)充。