Tuesday, February 2, 2021

Android Template Method

 

5. 应用场景

  • 一次性实现算法的执行顺序和固定不变部分,可变部分则交由子类来实现。
  • 多个子类中拥有相同的行为时,可以将其抽取出来放在父类中,避免重复的代码。
  • 使用钩子方法来让子类决定父类的某个步骤是否执行,实现子类对父类的反向控制。
  • 控制子类扩展。模板方法只在特定点调用钩子方法,这样就只允许在这些点进行扩展。

6. 优点

  • 提高代码复用性,去除子类中的重复代码。
  • 提高扩展性,不同实现细节放到不同子类中,易于增加新行为。

7. 缺点

每个不同的实现都需要定义一个子类,这会导致类的个数的增加,设计更加抽象。


Android中的源码分析

Android中 View 的 draw 方法就是使用了模板方法模式:

View的draw方法

===================================================================

public class View{
    //钩子方法,空实现
    protected void onDraw(Canvas canvas) {
    }
    //钩子方法,空实现
    protected void dispatchDraw(Canvas canvas) {
    }
    //绘制方法,定义绘制流程
    public void draw(Canvas canvas) {
       //其他代码略

        /*
         *  绘制流程如下:
         *
         *      1. 绘制view背景
         *      2. 如果有需要,就保存图层
         *      3. 绘制view内容
         *      4. 绘制子View
         *      5. 如果有必要,绘制渐变框和恢复图层
         *      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内容

            dispatchDraw(canvas);//步骤4. 绘制子View

            // 覆盖一部分内容,绘制前景
            if (mOverlay != null && !mOverlay.isEmpty()) {
                mOverlay.getOverlayView().dispatchDraw(canvas);
            }

            onDrawForeground(canvas); //步骤6. 绘制装饰(滑动条等)

            return;
        }
}

===================================================================

说明

  • Viewdraw()方法中定义了一整套的绘制流程,这个流程是固定的,所有的Android中的View都是按照这个流程来绘制的。其中drawBackground()这个方法在View类中是实现了具体过程的,而onDraw()方法和dispatchDraw()方法在View中都是空实现,即都是钩子方法。不同的子类通过重写这些空实现来实现自身不同的绘制效果。
  • 具体的View,像TextView这些单一的View,就会重写onDraw()方法,由于TextView没有子View,所以dispatchDraw()还是空实现;而ViewGroup类含有子View,需要遍历子View并绘制,因此需要重写onDraw()dispatchDraw()
  • 所以,我们自定义View时必须且只需重写onDraw();自定义ViewGroup时则需要重写onDraw()dispatchDraw()

  • No comments:

    Post a Comment

    n8n index

     【n8n免費本地端部署】Windows版|程式安裝x指令大補帖  【一鍵安裝 n8n】圖文教學,獲得無限額度自動化工具&限時免費升級企業版功能