• java设计模式-模板方法模式


    1.模板方法(Template Method)模式的定义

    • 它定义一个操作中的算法的框架,而将一些步骤延迟到了子类中。使得子类可以不改变一个算法的结构即可重定义该算法的某些步骤。它是一种类行为型模式。

    2.模板方法模式的优缺点

    优点:

    • 良好的封装性。把公有的不变的方法封装在父类,而子类负责实现具体逻辑。
    • 良好的扩展性。增加功能由子类实现基本方法扩展,符合单一职责原则和开闭原则。
    • 它在父类中提取了公共的部分代码,便于复用代码。

    缺点:

    • 对每个不同的实现都需要定义一个子类,这会导致类的个数增加,系统更加庞大,设计也更加抽象。
    • 父类中的抽象方法由子类实现,子类执行的结果会影响父类的结果,这导致一种反向的控制结构,它提高了代码阅读的难度。

    3.模板方法模式主要角色

      3.1 抽象类(Abstract Class):负责给出一个算法的轮廓和骨架。它由一个模板方法和若干个基本方法构成。这些方法的定义如下:

        3.1.1 模板方法:定义了算法的骨架,按某种顺序调用其包含的基本方法。

        3.1.2 基本方法:是整个算法中的一个步骤,包含以下几种类型:

          抽象方法:在抽象类中申明,由具体子类实现。

          具体方法:在抽象类中已经实现,在具体子类中可以继承或重写它。

          钩子方法:在抽象类中已经实现,包括用于判断的逻辑方法和需要子类重写的空方法两种。

      3.2 具体子类(Concrete Class):实现抽象类中所定义的抽象方法和钩子方法,它们是一个顶级逻辑的一个组成步骤。

    4.模板方法模式的结构图

    5.模板方法模式的实现,以房子构建模板为例

    • 定义抽象类:房子构建模板
    package com.lw.designpattern.templatemethod;
    
    /**
     * @Classname HouseTemplate
     * @Description 定义抽象类(房子构建模板):
     *  负责给出一个算法的轮廓和骨架。它由一个模板方法和若干个基本方法构成。
     * @Author lw
     * @Date 2020-01-14 14:18
     */
    public abstract class HouseTemplate {
    
        /** 房子构建模板名称 */
        protected String templateName;
    
        protected HouseTemplate(String templateName) {
            this.templateName = templateName;
        }
    
        /** 模板方法则使用protected修饰,表明其需要在子类中实现 */
        /** 构建门 */
        protected abstract void buildDoor();
        /** 构建窗户 */
        protected abstract void buildWindow();
        /** 构建墙 */
        protected abstract void buildWall();
        /** 构建基地 */
        protected abstract void buildBase();
        /** 构建厕所 */
        protected abstract void buildToilet();
    
        /**
         * 钩子方法:给予授权,判断是否要执行
         *
         * @return boolean
         */
        protected boolean isBuildToilet() {
            return true;
        }
    
        /**
         * 基本方法:构建房子。用final修饰,保证其不会被子类修改
         */
        public final void buildHouse() {
            buildDoor();
            buildWindow();
            buildWall();
            buildBase();
            if (isBuildToilet()) {
                buildToilet();
            }
        }
    }
    • 创建具体子类:房子构建模板one,继承HouseTemplate抽象类
    package com.lw.designpattern.templatemethod;
    
    /**
     * @Classname HouseOne
     * @Description 具体子类房子构建模板one:实现抽象类中所定义的抽象方法和钩子方法
     * @Author lw
     * @Date 2020-01-14 14:37
     */
    public class HouseOne extends HouseTemplate {
    
        /** 是否需要构建厕所标志 */
        public boolean isBuildToilet;
    
        public HouseOne(String templateName) {
            super(templateName);
        }
    
        public HouseOne(String templateName, boolean isBuildToilet) {
            this(templateName);
            this.isBuildToilet = isBuildToilet;
        }
    
        @Override
        protected void buildDoor() {
            System.out.println(templateName +"的门要采用防盗门");
        }
    
        @Override
        protected void buildWindow() {
            System.out.println(templateName + "的窗户要面向北方");
        }
    
        @Override
        protected void buildWall() {
            System.out.println(templateName + "的墙使用大理石建造");
        }
    
        @Override
        protected void buildBase() {
            System.out.println(templateName + "的地基使用钢铁地基");
        }
    
        @Override
        protected void buildToilet() {
            System.out.println(templateName + "的厕所建在东南角");
        }
    
        @Override
        protected boolean isBuildToilet() {
            return isBuildToilet;
        }
    }
    • 再创建一个具体子类:房子构建模板two,继承HouseTemplate抽象类
    package com.lw.designpattern.templatemethod;
    
    /**
     * @Classname HouseTwo
     * @Description 具体子类房子构建模板two:实现抽象类中所定义的抽象方法和钩子方法
     * @Author lw
     * @Date 2020-01-14 14:37
     */
    public class HouseTwo extends HouseTemplate {
    
        public HouseTwo(String templateName) {
            super(templateName);
        }
    
        @Override
        protected void buildDoor() {
            System.out.println(templateName + "的门采用木门");
        }
    
        @Override
        protected void buildWindow() {
            System.out.println(templateName + "的窗户要向南");
        }
    
        @Override
        protected void buildWall() {
            System.out.println(templateName + "的墙使用玻璃制造");
        }
    
        @Override
        protected void buildBase() {
            System.out.println(templateName + "的地基使用花岗岩");
        }
    
        @Override
        protected void buildToilet() {
            System.out.println(templateName + "的厕所建在西北角");
        }
    }
    • 单元测试
      /**
         * 模板方法模式
         */
        @Test
        public void testTemplateMethod() {
            // 创建房子模板对象
            HouseTemplate houseOne = new HouseOne("房子模板one", false);
            HouseTemplate houseTwo = new HouseTwo("房子模板two");
            // 房子构建模板
            System.out.println("=== 房子模板one,构建模板 ===");
            houseOne.buildHouse();
            System.out.println("=== 房子模板two,构建模板 ===");
            houseTwo.buildHouse();
        }

    结果打印

    通过执行结果我们可以清晰的看到,通过重写钩子方法自定义了房子模板one不需要构建厕所(fasle)。

    6.模板方法模式的应用场景

    • 在多个子类中拥有相同的方法,而且逻辑相同时,可以将这些方法抽出来放到一个模板抽象类中。
    • 程序主框架相同,细节不同的情况下,也可以使用模板方法。
  • 相关阅读:
    (转)linux书籍推荐
    (转)X Windows与GNOME,KDE的关系
    (转)学习Linux编程开发必读书籍
    (转)详解C中volatile关键字
    博客开张了
    VMware虚拟产品简介
    c++ eof()
    旋转矩阵
    VMware文件辨别
    Microsoft HTTPAPI/2.0 use Port 80 – 无法启动WAMP Apache
  • 原文地址:https://www.cnblogs.com/lwcode6/p/12191728.html
Copyright © 2020-2023  润新知