Android源码学习之模板方法模式应用

摘要:
模板方法允许子类在不改变算法结构的情况下重新定义算法的某些特定步骤。

一、模板方法模式定义

模板方法模式定义:
defines the skeleton of an algorithm in a method, deferring some steps to subclasses. Template Method lets subclasses redefine certain steps of an algorithm without changing the algorithm's structure.
定义一个方法操作算法的框架(骨架结构),而将一些步骤延迟到子类中。模板方法使子类可以在不改变一个算法的结构的情况下,就可以重定义该算法的某些特定步骤。

Android源码学习之模板方法模式应用第1张

  如上图所示(截取自《Head First Design Patterns》一书),具体各个部分有什么作用见上图,这里就不啰嗦了。

二、模板方法模式优势

封装不变部分,扩展可变部分。把不变部分的算法封装到父类实现,而可变部分的根据子类的具体需要,则可以通过继承来扩展。

提取公共部分,构成一个“模板”,模板的作用在于对算法或者流程的一个结构化、规范化,子类不能修改“模板方法”的整个算法骨架或者流程的顺序等,只能根据自身的不同,对模板方法中算法的某一步进行扩展。

行为由父类控制,子类实现。子类可以通过扩展的方法增加相应的功能,符合开闭原则。

三、模板方法模式在Android源码中的应用

  在Android源码中,View中的Draw()方法就是一个“模板方法”。它定义了一系列“Draw”过程,主要包括这几个步骤(截取自源代码):

        /*
         * 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)
         */

具体函数代码如下所示:

Android源码学习之模板方法模式应用第2张View Code

其中第三步( 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显示效果和别的具体子类的不同。现在来看看继承自View类的具体子类如何扩展Draw()模板方法显示自己的与众不同:

Android源码学习之模板方法模式应用第7张

  1、TextView类中重写了OnDraw函数

复制代码
@Override
    protected void onDraw(Canvas canvas) {
        if (mPreDrawState == PREDRAW_DONE) {
            final ViewTreeObserver observer = getViewTreeObserver();
            observer.removeOnPreDrawListener(this);
            mPreDrawState = PREDRAW_NOT_REGISTERED;
        }

        if (mCurrentAlpha <= ViewConfiguration.ALPHA_THRESHOLD_INT) return;

        restartMarqueeIfNeeded();

        // Draw the background for this view
        super.onDraw(canvas);

        final int compoundPaddingLeft = getCompoundPaddingLeft();
        final int compoundPaddingTop = getCompoundPaddingTop();
        final int compoundPaddingRight = getCompoundPaddingRight();
        final int compoundPaddingBottom = getCompoundPaddingBottom();
        final int scrollX = mScrollX;
        final int scrollY = mScrollY;
        final int right = mRight;
        final int left = mLeft;
        final int bottom = mBottom;
        final int top = mTop;

        final Drawables dr = mDrawables;
        if (dr != null) {
            /*
             * Compound, not extended, because the icon is not clipped
             * if the text height is smaller.
。。。
}
复制代码

  2、SurfaceView重写了dispatchDraw()函数:

复制代码
    @Override
    protected void dispatchDraw(Canvas canvas) {
        if (mWindowType != WindowManager.LayoutParams.TYPE_APPLICATION_PANEL) {
            // if SKIP_DRAW is cleared, draw() has already punched a hole
            if ((mPrivateFlags & SKIP_DRAW) == SKIP_DRAW) {
                // punch a whole in the view-hierarchy below us
                canvas.drawColor(0, PorterDuff.Mode.CLEAR);
            }
        }
        super.dispatchDraw(canvas);
    }
复制代码

  3、ViewGroup类重写了dispatchDraw()函数:

复制代码
 @Override
    protected void dispatchDraw(Canvas canvas) {
        final int count = mChildrenCount;
        final View[] children = mChildren;
        int flags = mGroupFlags;

        if ((flags & FLAG_RUN_ANIMATION) != 0 && canAnimate()) {
            final boolean cache = (mGroupFlags & FLAG_ANIMATION_CACHE) == FLAG_ANIMATION_CACHE;

            final boolean buildCache = !isHardwareAccelerated();
            for (int i = 0; i < count; i++) {
                final View child = children[i];
                if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) {
                    final LayoutParams params = child.getLayoutParams();
                    attachLayoutAnimationParameters(child, params, i, count);
                    bindLayoutAnimation(child);
                    if (cache) {
                        child.setDrawingCacheEnabled(true);
                        if (buildCache) {                        
                            child.buildDrawingCache(true);
                        }
                    }
                }
            }

            final LayoutAnimationController controller = mLayoutAnimationController;
            if (controller.willOverlap()) {
                mGroupFlags |= FLAG_OPTIMIZE_INVALIDATE;
            }

            controller.start();

            mGroupFlags &= ~FLAG_RUN_ANIMATION;
            mGroupFlags &= ~FLAG_ANIMATION_DONE;

            if (cache) {
                mGroupFlags |= FLAG_CHILDREN_DRAWN_WITH_CACHE;
            }

            if 

免责声明:内容来源于网络,仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇B/S架构 Web打印程序(Argox)错误:Type referred to is not an annotation type: CacheFind下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

go 学习 (一):环境配置

Go 下载地址:https://golang.google.cn/dl/ 1、右键我的电脑 --> 左上方 “高级系统设置” ---> 环境变量 --> 第二个菜单栏 “系统变量” --> 找到变量名为 “Path” --> 双击并点击新建,添加 go/bin 目录 --> 点击确定才会生效 2、新建文件夹作为源码的...

[转]开发者必备的6款源码搜索引擎

From : http://news.cnblogs.com/n/184662/   英文原文:Open Source Matters: 6 Source Code Search Engines You Can Use For Programming Projects   在推动技术变革上,开源运动发挥了非常显著的作用。而 Linux 成功地将开源转换成...

如何在jenkins上新建一个项目及其简单配置

1.首先,点击【新建】进入选择页面,如下图(一般选择“构建一个自由风格的软件项目”)     2.填好项目名称后,点击ok,跳转至如下页面,可以在这个页面进行项目的配置(包括拉源码、修改持续构建时间、打包部署前修改配置文件等) 3.General中的“丢弃旧的构建”可以设定持续构建的 4.在“参数化构建过程”中可以设置要构建的版本有哪些,如下  5...

深入理解Faiss 原理&amp;amp;源码 (一) 编译

目录 深入理解Faiss 原理&源码 (一) 编译 mac下安装 安装mac xcode工具包 安装 openblas 安装swig 安装libomp 编译faiss 附录 深入理解Faiss 原理&源码 (一) 编译 Faiss系列, 从单机lib到构建大规模分布式向量检索系统, 且听我娓娓道来 Faiss是什么? F...

chromium浏览器开发系列第三篇:chromium源码目录结构

上两篇介绍了下载源码和编译源码,这次主要介绍chromium的源码目录结构,我也是通过源码和官网结合来跟大家说,如果有说的不准确的,欢迎交流。 另外,官网的不一定准确,他们其实也很懒,所以最主要还是靠自己。官网只能作为一个参考。 Chromium结构相对两年前变化很大。目录结构依然很清晰,主要有三个部分(不包括其他的库):浏览器,渲染器,webkit。浏览...

java ssm 后台框架平台 项目源码 websocket即时聊天发图片文字 好友群组 SSM源码

官网 http://www.fhadmin.org/D 集成安全权限框架shiro  Shiro 是一个用 Java 语言实现的框架,通过一个简单易用的 API 提供身份验证和授权,更安全,更可靠E 集成ehcache分布式缓存  是一个纯Java的进程内缓存框架,具有快速、精干等特点,广泛使用的开源Java分布式缓存。F 集成微信接口开发,微信自定义菜单...