设计模式4 ——模板方法模式

一、模板方法模式的定义 

       Define the skeleton of an algorithm in an operation,deferring some steps to subclasses.Template Method lets of an algorithm without changing certain steps of an algorithm without changing the algorithm's structure.(定义一个操作中的算法的框架,而将一些步骤延迟到子类中,使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤)

二、模板方法模式的应用

1、模板方法模式的优点

      照实际习惯,抽象类负责声明抽象、最一般的事物属性和方法。但是模板方法却颠倒了,抽象类定义了部分抽象方法,由子类实现,子类执行的结果影响了父类的结果,也就是子类对父类产生了影响,这在复杂的项目中,带来阅读的难度,而且也会让新手产生不适感。

2、模板方法模式的缺点

       多个子类有公有的方法,并且逻辑基本相同时,重要、复杂的算法,可以把核心算法设计为模板方法,周边的细节功能则由各个子类实现。重构时,模板方法模式是一个经常使用的模式,把相同的代码放到父类中,然后通过钩子函数约束其行为。

        对每个不同的实现都需要定义一个子类,这会导致类的个数增加,系统更加庞大,设计也更加抽象,间接地增加了系统实现的复杂度。父类中的抽象方法由子类实现,子类执行的结果会影响父类的结果,这导致一种反向的控制结构,它提高了代码阅读的难度。由于继承关系自身的缺点,如果父类添加新的抽象方法,则所有子类都要改一遍。

3、模板方法模式的使用场景

算法的整体步骤很固定,但其中个别部分易变时,这时候可以使用模板方法模式,将容易变的部分抽象出来,供子类实现。当多个子类存在公共的行为时,可以将其提取出来并集中到一个公共父类中以避免代码重复。首先,要识别现有代码中的不同之处,并且将不同之处分离为新的操作。最后,用一个调用这些新的操作的模板方法来替换这些不同的代码。当需要控制子类的扩展时,模板方法只在特定点调用钩子操作,这样就只允许在这些点进行扩展。

 三、模板方法模式的写法

 

public abstract class AbstractDoctor {

    //了解病情
    protected abstract void knowAboutSymptoms();
    //分析病情
    protected abstract void analysisIllness();
    //治疗患者
    protected abstract void curePatient();
        
    public void work() {
        knowAboutSymptoms();
        analysisIllness();
        curePatient();
    }
}

public class ChineseDoctor extends AbstractDoctor {

    @Override
    protected void knowAboutSymptoms() {
        System.out.println("中医通过望闻问切了解病人病情");
    }
    @Override
    protected void analysisIllness() {
        System.out.println("得知病情后,通过自己丰富的经验分析病情,制定治疗方案");
    }
    @Override
    protected void curePatient() {
        System.out.println("根据治疗方案给你抓中药");
    }
}

public class WestDoctor extends AbstractDoctor {
    @Override
    protected void knowAboutSymptoms() {
        System.out.println("简单询问,就让你去拍个片");
    }

    @Override
    protected void analysisIllness() {
        System.out.println("根据x光片,分析病人病情,制定治疗方案");
    }

    @Override
    protected void curePatient() {
        System.out.println("打针,输液,药片各来一打,包治百病");
    }
}

模板方法模式的扩展

public abstract class AbstractDoctor {

    protected boolean checkIsCure =true;

    //了解病情
    protected abstract void knowAboutSymptoms();
    //分析病情
    protected abstract void analysisIllness();
    //治疗患者
    protected abstract void curePatient();

    //检查病人是否需要治疗,默认需要
    //钩子函数
    protected boolean checkIsCure(){
        return true;
    }

    public void work() {
        knowAboutSymptoms();
        analysisIllness();
        if (checkIsCure()){
            curePatient();
        }
    }

}


public class ChineseDoctor extends AbstractDoctor {

    @Override
    public void knowAboutSymptoms() {
        System.out.println("中医通过望闻问切了解病人病情");
    }
    @Override
    public void analysisIllness() {
        System.out.println("得知病情后,通过自己丰富的经验分析病情,制定治疗方案");
    }
    @Override
    public void curePatient() {
        System.out.println("根据治疗方案给你抓中药");
    }
    @Override
    protected boolean checkIsCure(){
        return super.checkIsCure;
    }

    protected void setCheckIsCure(boolean isCure){
        super.checkIsCure=isCure;
    }
}

 

四、模板方法模式源码中的应用

Android中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;
        }
}

另外,像Activity的生命周期,AsyncTask等等也是用到了模板方法模式。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值