首页 > 其他分享 >模板方法模式总结

模板方法模式总结

时间:2022-09-24 13:23:18浏览次数:62  
标签:总结 System 模式 println 方法 public 模板 out

模板方法模式

近期在探究 Android 源码时,发现 Android 里面用到了大量的钩子方法,下意识反应这是一种设计模式的应用——模板方法,于是重新翻阅了刘伟老师的《Java设计模式》,趁着摸鱼时间对该设计模式做个简单总结。

举个现实生活中的例子,做便当(我每天做)。通常情况下,做便当的步骤基本比较固定:准备食材 —》处理食材 —》完成打包 。在这过程中,购买食材和打包的过程大同小异,而对食材的处理过程则存在巨大差异,而在软件开发中同样存在类似问题,这就衍生出了我们今天介绍的设计模式——模板方法模式。

模式简介

模板方法模式:定义一个操作中算法的框架,而将一些步骤延迟到子类中。模板方法模式使得一个子类可以不改变一个算法的结构即可重定义该方法的某些特定步骤。

模板方法是最简单的 行为型 设计模式,在其结构中只存在父类和子类之间的继承关系。其只有两个角色:抽象类和具体类。

  1. 抽象类(AbstractClass):定义了一系列的基本操作,子类可以重写这些基本方法;另外还实现了一个模板方法。
  2. 具体类(ConcreteClass):继承抽象类,实现抽象类的抽象基本操作,另外也可以重写抽象类中实现的基本方法。

实现说明

在模板方法模式中,抽象类负责描述一个算法的整体框架和流程,其子类负责具体过程实现。抽象类中定义的方法为基本方法,实现算法的逻辑步骤,而将基本步骤汇总起来的方法称之为模板方法,该模式的名字也因此而来。

模板方法

一个具体方法,由抽象类声明和实现,并被子类完成继承下来,实现了算法逻辑框架。由于模板方法是具体方法,因此模板方法模式的抽象层只能是抽象层。

基本方法

基本方法可以分为抽象方法、具体方法和钩子方法。其中抽象方法由抽象类声明、具体子类实现;具体方法可由抽象类或具体类声明和实现,子类可重写具体方法。钩子方法可由抽象类或具体类声明和实现,子类可重写钩子方法。

在模板方法模式中,钩子方法通常有两种实现方式,一种是实现体为空,另外是作为具体步骤的实现的判断条件,称之为 "挂钩"。这类钩子方法通常返回类型为 boolean 类型,方法名一般为 isXXX(),如:

//模板方法
public void templateMethod(){
    step1();
    step2();
    //通过钩子方法判断是否执行下一步
    if(isToNext){ step3(); }
}

//钩子方法
public boolean isToNext(){
    return true;
}

应用实例

image-20220911214403199

  1. 抽象类——Bento

    /**
     * 准备便当:
     * 准备食材 —》处理食材 —》完成打包
     */
    public abstract class Bento {
    
        protected String bentoName;
    
        protected String[] ingredients;
    
        public Bento(String bentoName,String... ingredients){
            this.bentoName = bentoName;
            this.ingredients = ingredients;
            System.out.println("做一份"+bentoName+"便当");
        }
    
        //模板方法
        public void make(){
            //1.准备食材
            prepare(ingredients);
            //2.处理食材
            handling();
            //3.完成打包
            if(isPackaging()) {
                packaging(bentoName);
            }
        }
    
        /**
         * 准备食材
         */
        public void prepare(String... Ingredients){
            System.out.println( "准备:"+ Arrays.toString(Ingredients));
        }
    
        /**
         * 处理食材
         */
        public abstract void handling();
    
        /**
         * 完成打包
         */
        public void packaging(String bentoName){
            System.out.println("打包:" + bentoName);
        }
    
        //钩子方法
        public boolean isPackaging(){
            return true;
        }
    }
    
  2. 具体类——BraisedChicken、LettuceWithOyster、TomatoWithEgg

    • BraisedChicken
    /**
     * 黄焖鸡腿
     * */
    public class BraisedChicken extends Bento{
    
        public BraisedChicken() {
            super("黄焖鸡腿", "鸡腿","生姜","香菇","料酒","盐");
        }
         
        @Override
     public void handling() {
            System.out.println("处理:1.腌制鸡腿");
            System.out.println("     2.加入料酒、生姜、香菇焖煮");
            System.out.println("     3.加盐调味关火");
     }
    }
    
    • LettuceWithOyster
    /**
     * 蚝油生菜
     * */
    public class LettuceWithOyster extends Bento{
    
        public LettuceWithOyster() {
            super("蚝油生菜", "生菜","蚝油","大蒜","鲜味汁","盐");
        }
    
        @Override
        public void handling() {
            System.out.println("处理:1.焯生菜");
            System.out.println("     2.炒蒜末");
            System.out.println("     3.蚝油、鲜味汁加盐调汁");
            System.out.println("     4.大火收汁关火");
            System.out.println("     5.生菜淋调味汁");
        }
    
        //重写钩子方法
        @Override
        public boolean isPackaging(){
            return false;
        }
    }
    
    • TomatoWithEgg
    /**
     * 西红柿炒鸡蛋
     * */
    public class TomatoWithEgg extends Bento{
    
        public TomatoWithEgg() {
            super("西红柿炒鸡蛋", "西红柿","鸡蛋","糖","盐");
        }
    
        @Override
        public void handling() {
            System.out.println("处理:1.炒鸡蛋");
            System.out.println("     2.炒西红柿");
            System.out.println("     3.加糖和盐");
            System.out.println("     4.收汁关火");
        }
    }
    
  3. 客户端

    public class MainTest {
    
        public static void main(String[] args) {
            //做份西红柿炒蛋便当
            Bento bento01 = new TomatoWithEgg();
            bento01.make();
    
            //做份蚝油生菜便当
            Bento bento02 = new LettuceWithOyster();
            bento02.make();
    
            //做份黄焖鸡腿便当
            Bento bento03 = new BraisedChicken();
            bento03.make();
        }
    }
    

模式总结

优点

  1. 使用父类形式化定义一个算法,子类处理细节实现,细节处理过程中不影响父类的定义的算法执行顺序。
  2. 子类通过覆盖钩子方法可实现反向控制父类的算法执行步骤,具有良好的扩展性,符合单一职责和开闭原则。

缺点

由于每个具体方法不同实现都需要提供一个子类,如果父类中可变方法过多,将会导致类的数量增多,使系统变得庞大。

应用场景

  1. 一次性实现一个算法的不变部分,并将可变行为留给子类实现。
  2. 通过子类来决定父类算法中的某个步骤是可执行的,实现子类对父类的反向控制。

参考书籍:《Java设计模式》/ 刘伟 编著 | 清华大学出版社

标签:总结,System,模式,println,方法,public,模板,out
From: https://www.cnblogs.com/xiaobaiLX/p/16725465.html

相关文章

  • 模板分文件编写,CUDA打印
    ifndefFUN_HPPdefineFUN_HPPifdefined(USE_EXPORT)defineEXPORTexportelsedefineEXPORTendifEXPORTtemplatevoidprint_typeof(Tconst&);if!defined(US......
  • 本周总结9.24
    这周确实是非常累的一周,基本一直在学习和配置Hbase相关的东西。初学大数据相关的东西最难的就是开始的配置环境了,由于对linux系统命令的不熟悉,配置就花费了3天的时间。我刚......
  • 吃透JAVA的Stream流操作,多年实践总结
    在JAVA中,涉及到对数组、Collection等集合类中的元素进行操作的时候,通常会通过循环的方式进行逐个处理,或者使用Stream的方式进行处理。例如,现在有这么一个需求:从给定句子......
  • java设计模式之七大原则
    java设计模式 以下内容为本人的学习笔记,如需要转载,请声明原文链接   https://www.cnblogs.com/lyh1024/p/16724932.html 设计模式1.设计模式的目的编写软件过......
  • 纯注解开发模式
    定义bean:   纯注解开发模式:用SpringConfig类来代替applicationContext.xml配置文件,利用注解@configuration代表了xml里的基本配置,在SpringConfig类中再加一个注解@......
  • 前端面试经常被问的题目,自己总结了一下
    JavaScript为什么要进行变量提升,它导致了什么问题?变量提升的表现是,无论在函数中何处位置声明的变量,好像都被提升到了函数的首部,可以在变量声明前访问到而不会报错。造成......
  • 总结一下最近前端面试被问到的题目吧
    浏览器乱码的原因是什么?如何解决?产生乱码的原因:网页源代码是gbk的编码,而内容中的中文字是utf-8编码的,这样浏览器打开即会出现html乱码,反之也会出现乱码;html网页编码是g......
  • 20220923测试总结
    P3216[HNOI2011]数学作业原题链接题目分析细心的话你是能够看出以下递推式的(我不够细心):\[F_n=F_{n-1}+10^k+n\]其中\(k=\lfloor\log_{10}n\rfloor\)硬性递推\(O(n^......
  • 代码随想录训练营|Day 4|202,19,面试题 02.07,142,总结
    24.SwapNodesinPairsGivena linkedlist,swapeverytwoadjacentnodesandreturnitshead.Youmustsolvetheproblemwithout modifyingthevaluesinth......
  • [原创] 关于模式识别模型有效性的验证——交叉验证Cross Validation
    作者:StevenYang([email protected])什么是交叉验证(CrossValidation)?比如有100条数据,一部分作为训练集,一部分作为测试集。用训练集(一般大于50%)进行训练,然后用......