android 模板设计,Android的设计模式-模板方法模式
前言
Android的設(shè)計模式系列文章介紹,歡迎關(guān)注,持續(xù)更新中:
1.定義
定義一個操作中的算法框架,而將一些步驟延遲到子類中,使得子類可以不改變一個算法的結(jié)構(gòu)即可重定義算法的某些特定步驟。
2.介紹
模板方法模式屬于行為型模式。
模板方法模式主要是用來定義一套流程下來的固定步驟,而具體的步驟實(shí)現(xiàn)則可以是不固定的。
3.UML類圖
模板方法UML類圖.jpg
角色說明:
AbstractClass(抽象類):,定義了一整套算法框架。
ConcreteClass(具體實(shí)現(xiàn)類):具體實(shí)現(xiàn)類,根據(jù)需要去實(shí)現(xiàn)抽象類中的方法。
4.實(shí)現(xiàn)
繼續(xù)以送快遞為例,快遞員送快遞基本就是一套固定的流程:收到快遞,準(zhǔn)備派送->聯(lián)系收貨人->確定結(jié)果。
4.1 創(chuàng)建抽象類
定義算法框架,這里是快遞員派送快遞的步驟:
public abstract class Postman {//抽象快遞員類
//派送流程
public final void post() {//這里申明為final,不希望子類覆蓋這個方法,防止更改流程的執(zhí)行順序
prepare();//準(zhǔn)備派送
call();//聯(lián)系收貨人
if (isSign())//是否簽收
sign();//簽收
else refuse();//拒簽
}
protected void prepare() {//準(zhǔn)備操作,固定流程,父類實(shí)現(xiàn)
System.out.println("快遞已達(dá)到,準(zhǔn)備派送");
}
protected abstract void call();//聯(lián)系收貨人,聯(lián)系人不一樣,所以為抽象方法,子類實(shí)現(xiàn)
protected boolean isSign() {//是否簽收,這個是鉤子方法,用來控制流程的走向
return true;
}
protected void sign() {//簽收,這個是固定流程,父類實(shí)現(xiàn)
System.out.println("客戶已簽收,上報系統(tǒng)");
}
protected void refuse() {//拒簽,空實(shí)現(xiàn),這個也是鉤子方法,子類可以跟進(jìn)實(shí)際來決定是否去實(shí)現(xiàn)這個方法
}
}
需要注意的是上面的抽象類(Postman)包含了三種類型的方法:抽象方法、具體方法和鉤子方法。
抽象方法:需要子類去實(shí)現(xiàn)。如上面的call()。
具體方法:抽象父類中直接實(shí)現(xiàn)。如上面的prepare()和sign()。
鉤子方法:有兩種,第一種,它是一個空實(shí)現(xiàn)的方法,子類可以視情況來決定是否要覆蓋它,如上面的refuse();第二種,它的返回類型通常是boolean類型的,一般用于對某個條件進(jìn)行判斷,如果條件滿足則執(zhí)行某一步驟,否則將不執(zhí)行,如上面的isSign()。
4.2 創(chuàng)建具體實(shí)現(xiàn)類
根據(jù)需要去實(shí)現(xiàn)抽象類中的方法,下面以派送給兩個不同的人為例,其中一個簽收,另一個拒收:
public class PostA extends Postman {//派送給A先生
@Override
protected void call() {//聯(lián)系收貨,實(shí)現(xiàn)父類的抽象方法
System.out.println("聯(lián)系A(chǔ)先生并送到門口");
}
}
public class PostB extends Postman {//派送給B先生
@Override
protected void call() {//聯(lián)系收貨,實(shí)現(xiàn)父類的抽象方法
System.out.println("聯(lián)系B先生并送到門口");
}
@Override
protected boolean isSign() {//是否簽收,覆蓋父類的鉤子方法,控制流程的走向
return false;
}
@Override
protected void refuse() {//拒簽,覆蓋父類的鉤子方法
System.out.println("拒絕簽收:商品不符");
}
}
4.3 客戶端測試
public void test(){
System.out.println("----派送A----");
Postman postA=new PostA();
postA.post();
System.out.println("----派送B----");
Postman postB=new PostB();
postB.post();
}
輸出結(jié)果:
----派送A----
快遞已達(dá)到,準(zhǔn)備派送
聯(lián)系A(chǔ)先生并送到門口
客戶已簽收,上報系統(tǒng)
----派送B----
快遞已達(dá)到,準(zhǔn)備派送
聯(lián)系B先生并送到門口
拒絕簽收:商品不符
5. 應(yīng)用場景
一次性實(shí)現(xiàn)算法的執(zhí)行順序和固定不變部分,可變部分則交由子類來實(shí)現(xiàn)。
多個子類中擁有相同的行為時,可以將其抽取出來放在父類中,避免重復(fù)的代碼。
使用鉤子方法來讓子類決定父類的某個步驟是否執(zhí)行,實(shí)現(xiàn)子類對父類的反向控制。
控制子類擴(kuò)展。模板方法只在特定點(diǎn)調(diào)用鉤子方法,這樣就只允許在這些點(diǎn)進(jìn)行擴(kuò)展。
6. 優(yōu)點(diǎn)
提高代碼復(fù)用性,去除子類中的重復(fù)代碼。
提高擴(kuò)展性,不同實(shí)現(xiàn)細(xì)節(jié)放到不同子類中,易于增加新行為。
7. 缺點(diǎn)
每個不同的實(shí)現(xiàn)都需要定義一個子類,這會導(dǎo)致類的個數(shù)的增加,設(shè)計更加抽象。
8. Android中的源碼分析
Android中View的draw方法就是使用了模板方法模式:
8.1 View的draw方法
public class View{
//鉤子方法,空實(shí)現(xiàn)
protected void onDraw(Canvas canvas) {
}
//鉤子方法,空實(shí)現(xiàn)
protected void dispatchDraw(Canvas canvas) {
}
//繪制方法,定義繪制流程
public void draw(Canvas canvas) {
//其他代碼略
/*
* 繪制流程如下:
*
* 1. 繪制view背景
* 2. 如果有需要,就保存圖層
* 3. 繪制view內(nèi)容
* 4. 繪制子View
* 5. 如果有必要,繪制漸變框和恢復(fù)圖層
* 6. 繪制裝飾(滑動條等)
*/
if (!dirtyOpaque) {
drawBackground(canvas);//步驟1. 繪制view背景
}
// 如果可能的話跳過第2步和第5步(常見情況)
final int viewFlags = mViewFlags;
boolean horizontalEdges = (viewFlags & FADING_EDGE_HORIZONTAL) != 0;
boolean verticalEdges = (viewFlags & FADING_EDGE_VERTICAL) != 0;
if (!verticalEdges && !horizontalEdges) {
if (!dirtyOpaque) onDraw(canvas);//步驟3. 繪制view內(nèi)容
dispatchDraw(canvas);//步驟4. 繪制子View
// 覆蓋一部分內(nèi)容,繪制前景
if (mOverlay != null && !mOverlay.isEmpty()) {
mOverlay.getOverlayView().dispatchDraw(canvas);
}
onDrawForeground(canvas); //步驟6. 繪制裝飾(滑動條等)
return;
}
}
8.2 說明
View的draw()方法中定義了一整套的繪制流程,這個流程是固定的,所有的Android中的View都是按照這個流程來繪制的。其中drawBackground()這個方法在View類中是實(shí)現(xiàn)了具體過程的,而onDraw()方法和dispatchDraw()方法在View中都是空實(shí)現(xiàn),即都是鉤子方法。不同的子類通過重寫這些空實(shí)現(xiàn)來實(shí)現(xiàn)自身不同的繪制效果。
具體的View,像TextView這些單一的View,就會重寫onDraw()方法,由于TextView沒有子View,所以dispatchDraw()還是空實(shí)現(xiàn);而ViewGroup類含有子View,需要遍歷子View并繪制,因此需要重寫onDraw()和dispatchDraw()。
所以,我們自定義View時必須且只需重寫onDraw();自定義ViewGroup時則需要重寫onDraw()和dispatchDraw()。
8.3 其他
另外,像Activity的生命周期,AsyncTask等等也是用到了模板方法模式,也興趣的可以研究一下。
總結(jié)
以上是生活随笔為你收集整理的android 模板设计,Android的设计模式-模板方法模式的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Java 操作Word书签(二):添加文
- 下一篇: c语言办公用品管理系统,恒达办公用品管理