设计模式之模板方法模式

java程序的设计原则

6大原则:

单一职责:一个类和方法只做一件事。
开闭原则:对修改关闭,对扩展开发。
里氏替换原则:子类可扩展新方法,但不可修改父类已有方法(父类已提供了具体实现的方法)。
依赖倒置:依赖于抽象,而非具体实现,即面向接口编程(如方法参数,类属性使用接口声明,这样可接收任何子类)。
接口隔离:使用多个隔离的接口定义抽象,降低耦合。
最少知道/迪米特原则:降低类之间的依赖,聚合,组合等。

1:模板方法设计模式

模板方法设计模式是行为型设计模式中的一种,用在一个功能的完成需要经过一系列步骤,这些步骤是固定的,但是中间某些步骤具体行为是待定的,在不同的场景中行为不同,此时就可以考虑使用模板方法设计模式来完成,不同的场景对因不同的子类实现。

模板方法包含如下的角色:

抽象类/抽象模板(Abstract Class):负责给出一个算法的轮廓,由一个模板方法和若干个基本方法构成,这些方法定义如下
    1:模板方法(该方法也正是模式的核心),定义算法的框架,按照某种顺序调用其中的基本方法。
    2:基本方法,可以包含如下的几种类型
        抽象方法:由具体的子类实现,作为定制行为,因为是抽象方法所以子类必须实现。
        具体方法:在抽象类中已经提供了具体的实现,一般设置为private。
        钩子方法:在抽象类中已经提供了实现(一般是空实现),类似于抽象方法,但是并非强制子类实现,因为已经提供了默认实现。
具体子类/具体实现(Concrete Class):必须实现抽象模板中的抽象方法,以及选择性的重载钩子方法。

UML图如下:

设计模式之模板方法模式_第1张图片

接下来通过程序实现UML图。

源码 。

1.1:抽象模板

// 抽象类
public abstract class AbstractClass {
    // 模板方法,提供公共的调用顺序,不允许子类override,所以设置为final
    public final void templateMethod() {
        specificMethod();
        abstractMethod1();
        abstractMethod2();
        hookMethod();
    }

    // 钩子方法,子类可根据实际情况选择是否要试下该方法
    public void hookMethod() {
    }

    // 具体方法,设置为private,避免子类override,并且不允许外部访问
    private void specificMethod() {
        System.out.println("抽象类中的具体方法被调用...");
    }

    // 抽象方法1
    public abstract void abstractMethod1();

    // 抽象方法2
    public abstract void abstractMethod2();
}

1.2:具体实现

public class ConcreteClass extends AbstractClass {
    public void abstractMethod1() {
        System.out.println("抽象方法1的实现被调用...");
    }

    public void abstractMethod2() {
        System.out.println("抽象方法2的实现被调用...");
    }

    @Override
    public void hookMethod() {
        System.out.println("钩子方法被调用...");
    }
}

1.3:客户端

public class TemplateMethodPattern {
    public static void main(String[] args) {
        AbstractClass tm = new ConcreteClass();
        tm.templateMethod();
    }
}

运行:

抽象类中的具体方法被调用...
抽象方法1的实现被调用...
抽象方法2的实现被调用...
钩子方法被调用...

Process finished with exit code 0

接下来我们再看一个实际生活中的例子。

2:出国留学

源码 。

分析:出国留学手续一般经过以下流程:索取学校资料,提出入学申请,办理因私出国护照、出境卡和公证,申请签证,体检、订机票、准备行装,抵达目标学校等,其中有些业务对各个学校是一样的,但有些业务因学校不同而不同,所以比较适合用模板方法模式来实现。

在本实例中,我们先定义一个出国留学的抽象类 StudyAbroad,里面包含了一个模板方法 TemplateMethod(),该方法中包含了办理出国留学手续流程中的各个基本方法,其中有些方法的处理由于各国都一样,所以在抽象类中就可以实现,但有些方法的处理各国是不同的,必须在其具体子类(如美国留学类 StudyInAmerica)中实现。如果再增加一个国家,只要增加一个子类就可以了,图 2 所示是其结构图。

设计模式之模板方法模式_第2张图片

2.1:StudyAbroad->抽象类

// 抽象类: 出国留学
public abstract class StudyAbroad {
    // 模板方法,设置为final不允许子类override
    public final void TemplateMethod() {
        // 索取学校资料
        lookingForSchool();
        // 入学申请
        applyForEnrol();
        // 办理因私出国护照、出境卡和公证
        applyForPassport();
        // 申请签证
        applyForVisa();
        // 体检、订机票、准备行装
        readyGoAbroad();
        // 抵达
        arriving();
    }

    // 具体方法,对外不可见,设置为private
    private void applyForPassport() {
        System.out.println("三.办理因私出国护照、出境卡和公证:");
    }

    // 具体方法,对外不可见,设置为private
    public void applyForVisa() {
        System.out.println("四.申请签证:");
    }

    // 具体方法,对外不可见,设置为private
    public void readyGoAbroad() {
        System.out.println("五.体检、订机票、准备行装:");
    }

    // 索取学校资料
    public abstract void lookingForSchool();

    // 入学申请
    public abstract void applyForEnrol();

    // 抵达
    public abstract void arriving();
}

2.2:StudyInAmerica->美国留学具体实现类

// 具体子类: 美国留学
public class StudyInAmerica extends StudyAbroad {
    @Override
    public void lookingForSchool() {
        System.out.println("一.索取学校以下资料(美国留学):");
    }

    @Override
    public void applyForEnrol() {
        System.out.println("二.入学申请(美国留学):");
    }

    @Override
    public void arriving() {
        System.out.println("六.抵达目标学校(美国留学):");
    }
}

2.3:StudyInVatican->梵蒂冈留学具体实现类

// 具体子类: 梵蒂冈留学
public class StudyInVatican extends StudyAbroad {
    @Override
    public void lookingForSchool() {
        System.out.println("一.索取学校以下资料(梵蒂冈):");
    }

    @Override
    public void applyForEnrol() {
        System.out.println("二.入学申请(梵蒂冈):");
    }

    @Override
    public void arriving() {
        System.out.println("六.抵达目标学校(梵蒂冈):");
    }
}

2.4:客户端

public class StudyAbroadProcess {
    public static void main(String[] args) {
        StudyAbroad tm = new StudyInAmerica();
        tm.TemplateMethod();

        System.out.println();
        System.out.println();

        StudyAbroad tm1 = new StudyInVatican();
        tm1.TemplateMethod();
    }
}

测试:

一.索取学校以下资料(美国留学):
二.入学申请(美国留学):
三.办理因私出国护照、出境卡和公证:
四.申请签证:
五.体检、订机票、准备行装:
六.抵达目标学校(美国留学):


一.索取学校以下资料(梵蒂冈):
二.入学申请(梵蒂冈):
三.办理因私出国护照、出境卡和公证:
四.申请签证:
五.体检、订机票、准备行装:
六.抵达目标学校(梵蒂冈):

Process finished with exit code 0

设计模式之模板方法模式_第3张图片

上图红色对钩的就是具体子类实现的逻辑。

参考文章列表

模板方法模式(模板方法设计模式)详解 。

秒懂设计模式之模板方法模式(Template Method Pattern) 。

你可能感兴趣的:(设计模式,模板方法模式,uml,java)