應用場景
在Android的代碼維護當中,經常會涉及到邏輯變更.但是又並不是整個邏輯變更了,往往是類似在之前的操作前面追加邏輯,或者是在之後追加邏輯.對於這樣的邏輯,往往是每個類型的操作裏面都要變更.
比較笨的方法當然就是挨個去寫啦.但是這種體力勞動太低效,太浪費了.在JAVA中,針對這樣的應用場景,比較常規的是有兩種處理方案:
1.繼承,重寫方法;
2.裝飾模式;
3.動態代理;
1.繼承
對於這種方式,是最簡單的方式.對於這個方式,大部分開發者都會很簡單的就想到.但是這個方式會造成很大部分的垃圾代碼,且靈活性並不高,而且還必須知道具體的類才能完成.示例如下:
1.1 寫一個普通的類實現一個普通的方法
由於這裏寫在外面類比較麻煩,所以就直接在一個類中用靜態內部類實現.
static class Man{
public void run(){
//一個正常人 跑步的方法
System.out.println("the man is running !");
}
}
1.2 寫一個類繼承這個類,進行增強
static class SuperMan extends Man{
@Override
public void run() {
//super.run();
System.out.println("the superMan is flying !");
}
}
1.3 運行測試
Man man = new SuperMan();
man.run();
//輸出結果 the superMan is flying !
2.裝飾模式
在不必改變原類文件和使用繼承的情況下,動態地擴展一個對象的功能。它是通過創建一個包裝對象,也就是裝飾來包裹真實的對象。
裝飾者模式,在java中的實現是通過接口來定義,包裝類和被包裝類實現同一個接口,包裝類持有被包裝類對象,包裝類就可以對被包裝類實現增強了.
2.1 接口類定義
interface Waiter{
void server();
}
2.2 被包裝類實現
static class Waitress implements Waiter{
@Override
public void server() {
System.out.println("Waitress server !");
}
}
2.3 包裝類實現
static class WaitessWrapper implements Waiter{
public Waiter waiter;
public WaitessWrapper(Waiter waiter) {
//爲了通用 持有接口類
this.waiter = waiter;
}
@Override
public void server() {
System.out.println("smile");
waiter.server();
System.out.println("smile end !");
}
}
2.4 調用函數
Waiter waiter1 = new Waitress();
waiter1.server();
Waiter waiter2 = new WaitessWrapper(waiter1);
waiter2.server();
//結果顯示如下
Waitress server !
smile
Waitress server !
smile end !
3.動態代理
代理機制及特點
1.通過實現 InvocationHandler 接口創建自己的調用處理器;
2.通過爲 Proxy 類指定 ClassLoader 對象和一組 interface 來創建動態代理類;
3.通過反射機制獲得動態代理類的構造函數,其唯一參數類型是調用處理器接口類型;
4.通過構造函數創建動態代理類實例,構造時調用處理器對象作爲參數被傳入。
由於主要目的是實現Android中的應用,因此我就直接附上項目代碼進行說明:
private void initListener() {
Object object = Proxy.newProxyInstance(this.getClass()
.getClassLoader(),
this.getClass()
.getInterfaces(),
(Object proxy, Method method, Object[] args) -> {
switch (method.getName()) {
case "onCategory":
case "onName":
case "onShare":
case "onPic":
case "onItemClick":
case "onRefresh":
case "onClick":
case "onOptionsItemSelected":
case "onNavigationItemSelected":
if (isEnvent) {
return null;
}
return method.invoke(NavActivity.this,
args);
case "onOption":
if (isEnvent) {
return null;
}
if (!TDevice.hasInternet()) {
showErrorTip(getString(R.string.footer_type_net_error));
return null;
}
if (WXShareManager.sWXAPI.getWXAppSupportAPI() <= WXShareManager.TIMELINE_SUPPORTED_VERSION) {
AppContext.showToast(R.string.weixin_update);
return null;
}
return method.invoke(NavActivity.this,
args);
}
return method.invoke(NavActivity.this, args);
});
mNavView.setNavigationItemSelectedListener((NavigationView.OnNavigationItemSelectedListener) object);
mFgtMainSrl.setOnRefreshListener((SwipeRefreshLayout.OnRefreshListener) object);
mAdapter.setListener((FileItemAdapter.OnFileItemListener) object);
mCreate.setOnClickListener((View.OnClickListener) object);
mScrollListener = new ScrollListener(null);
mFgtMainRv.addOnScrollListener(mScrollListener);
mCiv.setOnClickListener((View.OnClickListener) object);
mTvUser.setOnClickListener((View.OnClickListener) object);
mFusion.setOnClickListener((View.OnClickListener) object);
mDelete.setOnClickListener((View.OnClickListener) object);
mSeletedAll.setOnClickListener((View.OnClickListener) object);
}
如上,是我項目中的代碼.簡單說明一下:
1.標記位 isEnvent
是項目中當前是否有操作,在有操作的情況下應該避免別的操作.
2.Proxy.newProxyInstance
返回值 Object
是返回的當前操作執行返回的接口對象.
3.Proxy.newProxyInstance
中參數說明:如下是方法聲明
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException{}
參數一:ClassLoader loader
類加載器
參數二:Class<?>[] interfaces
代理接口
參數三:InvocationHandler h
對於代理接口的處理對象,主要代碼邏輯在這個類中實現,處理邏輯詳細看上述例子.
這樣實現可以最大限度的簡化代碼,解耦.而且這樣改起來也很方便.在後續代碼邏輯的變化中,主要邏輯寫在接口方法實現中,追加的邏輯都寫在代理對象裏面.可以方便隨時更改,而且比較統一,找起來也不復雜.