定义:定义一个方法操作算法的框架(骨架结构),而将一些步骤延迟到子类中。模板方法使子类可以在不改变一个算法的结构的情况下,就可以重定义该算法的某些特定步骤。
就像一个工厂车间的流水线一样,每一步其实都是可以固定的,就是具体的内容有些区别,这样就可以定义一个大致的流程框架,子类就直接按照这个框架来就可以了。
优点:
封装不变部分,扩展可变部分。把不变部分的算法封装到父类实现,而可变部分的根据子类的具体需要,则可以通过继承来扩展。
提取公共部分,构成一个“模板”,模板的作用在于对算法或者流程的一个结构化、规范化,子类不能修改“模板方法”的整个算法骨架或者流程的顺序等,只能根据自身的不同,对模板方法中算法的某一步进行扩展。
行为由父类控制,子类实现。子类可以通过扩展的方法增加相应的功能,符合开闭原则。
在Android源码中,View中的Draw()方法就是一个“模板方法”。它定义了一系列“Draw”过程,主要包括这几个步骤
public void draw(Canvas canvas) {
/*
* Draw traversal performs several drawing steps which must be executed
* in the appropriate order:
*
* 1. Draw the background
* 2. If necessary, save the canvas' layers to prepare for fading
* 3. Draw view's content
* 4. Draw children
* 5. If necessary, draw the fading edges and restore layers
* 6. Draw decorations (scrollbars for instance)
*/
// Step 1, draw the background, if needed
......
// skip step 2 & 5 if possible (common case)
......
if (!verticalEdges && !horizontalEdges) {
// Step 3, draw the content
if (!dirtyOpaque) onDraw(canvas);
// Step 4, draw the children
dispatchDraw(canvas);
// Step 6, draw decorations (scrollbars)
onDrawScrollBars(canvas);
// we're done...
return;
}
// Step 2, save the canvas' layers
......
// Step 3, draw the content
if (!dirtyOpaque) onDraw(canvas);
// Step 4, draw the children
dispatchDraw(canvas);
// Step 5, draw the fade effect and restore layers
......
canvas.restoreToCount(saveCount);
// Step 6, draw decorations (scrollbars)
onDrawScrollBars(canvas);
}
其中第三步( Step 3)Draw view’s content函数:
/**
* Implement this to do your drawing.
*
* @param canvas the canvas on which the background will be drawn
*/
protected void onDraw(Canvas canvas) {
}
第四步( Step 4) draw children
/**
* Called by draw to draw the child views. This may be overridden
* by derived classes to gain control just before its children are drawn
* (but after its own view has been drawn).
* @param canvas the canvas on which to draw the view
*/
protected void dispatchDraw(Canvas canvas) {
}
从上面的Draw()“模板方法”可以看出,当继承View子类中,如果要重写或者扩展这个方法时,整个方法流程和基本内容不能够修改,子类只能通过扩展onDraw(Canvas canvas)和dispatchDraw(Canvas canvas)两个函数,使子类自己的View显示效果和别的具体子类的不同。
另外,Android中的Activity也是使用了模板方法模式。这个比上面其实更明显。
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
@Override
protected void onRestart() {
super.onRestart();
}
@Override
protected void onStart() {
super.onStart();
}
@Override
protected void onResume() {
super.onResume();
}
@Override
protected void onPause() {
super.onPause();
}
@Override
protected void onStop() {
super.onStop();
}
@Override
protected void onDestroy() {
super.onDestroy();
}
}
在父类中实现一个算法不变的部分,并将可变的行为留给子类来实现。生命周期方法原本就是在基类中做出了Activity不同状态时回调的一系列方法,而这些方法具体需要做的可变部分交给子类去完成。
另外,Android中的AsyncTask也是一个典型的模板方法模式。
private class DownloadImageTask extends AsyncTask<String, Void, Bitmap> {
@Override
protected void onPreExecute() {
super.onPreExecute();
}
protected Bitmap doInBackground(String... urls) {
return loadImageFromNetwork(urls[0]);
}
@Override
protected void onProgressUpdate(Void... values) {
super.onProgressUpdate(values);
}
protected void onPostExecute(Bitmap result) {
mImageView.setImageBitmap(result);
}
@Override
protected void onCancelled() {
super.onCancelled();
}
}
我们在继承AsyncTask的时候只需要根据需要重新上面几个方法就可以,它们就是AsyncTask类的可变部分,我们在子类中只需要实现可变部分就可以了,不变部分AsyncTask已经实现了,所以我们只需要根据这个模板进行使用就行。
适用情况:
(1)一次性实现一个算法的不变部分,并将可变的行为留给子类去实现。
(2)各个子类中公共的行为应该被提取出来并且集中到一个公共的父类中去,这样避免了代码的重复。
(3)扩展子类的扩展。模板方法只在特定点调用操作,这样就只允许在这些点进行扩展。
参考文章:
Android源码学习之模板方法模式应用