模板方法设计模式(抽象类)

应用举例:模板方法设计模式(TemplateMethod)

抽象类体现的就是一种模板模式,抽象类作为多个子类的通用模板,子类在抽象类的基础上进行扩展、改造,但子类总体上会保留抽象类的行为方式。

解决的问题:

  • 当功能内部一部分实现是确定的,另一部分实现是不确定的。这时可以把不确定的部分暴露出去,让子类去实现。
  • 换句话说,在软件开发中实现一个算法时,整体步骤很固定、通用,这些步骤已经在父类中写好了。但是某些部分易变,易变部分可以抽象出来,供不同子类实现。这就是一种模板模式。

案例1:计算代码运行时间

  1. 创建一个Template模板类,其中代码(code)方法是不确定的,抽象出来,计算时间(spendTime)方法是确定的。
  2. 输出星号类(PrintStar)继承模板类,重写父类的code方法。
public class TemplateTest {public static void main(String[] args) {PrintStar ps = new PrintStar();ps.spendTime();}}abstract class Template {public void spendTime() {long start = System.currentTimeMillis();code();long end = System.currentTimeMillis();System.out.println("花费的时间为:" + (end - start));}public abstract void code();}class PrintStar extends Template {@Overridepublic void code() {System.out.println("*");System.out.println("**");System.out.println("***");System.out.println("****");System.out.println("*****");}}

案例2:银行流程抽象

  1. 创建一个银行模板抽象类BankTemplateMethod,该类中排队取号(takeNumber)、反馈评分(evaluate)方法是确定的,办理业务方法(transact)是不确定的,需要抽象出去由子类实现具体的业务。模板方法(process)调用流程是固定的。
  2. 取款类(DramMoney)继承银行模板类,重写父类的transact方法。
  3. 理财类(ManageMoney)继承银行模板类,重写父类的transact方法。
public class TemplateMethodTest {public static void main(String[] args) {BankTemplateMethod btm = new DramMoney();btm.process();BankTemplateMethod btm2 = new ManageMoney();btm.process();}}abstract class BankTemplateMethod {public void takeNumber() {System.out.println("排队取号");}//办理具体的业务public abstract void transact();public void evaluate() {System.out.println("反馈评分");}//模板方法public final void process() {takeNumber();transact();evaluate();}}class DramMoney extends BankTemplateMethod {@Overridepublic void transact() {System.out.println("我要取款!!!");}}class ManageMoney extends BankTemplateMethod {@Overridepublic void transact() {System.out.println("我要理财!!!我这里有200W");}}

案例三:抽象员工系统,分全职工和小时工,输出他们的工资(生日当月工资加二百)

  1. 创建员工抽象类(Employee),工资计算(calculateSalary)方法不确定需要抽象,是否为生日当月(isBirthday)方法、总工资计算(earnings)方法是确定的。
  2. 创建全职工类(SalariedEmployee)继承员工抽象类,重写工资计算(calculateSalary)方法。
  3. 创建小时工类(HourlyEmployee)继承员工抽象类,重写工资计算(calculateSalary)方法。

员工抽象类 Employee.java:

@Data@AllArgsConstructor@NoArgsConstructorpublic abstract class Employee {private String name;private Integer number;private MyDate birthday;public abstract double calculateSalary();public String toString() {return "name = " + name + ",number = " + number + ", birthday = " + birthday.toDateString();}//模板方法:返回工资public final double earnings() {return calculateSalary() + isBirthday();}public double isBirthday() {Calendar now = Calendar.getInstance();return birthday.getMonth() - 1 == now.get(Calendar.MONTH) ? 200 : 0;}}@Data@AllArgsConstructor@NoArgsConstructorclass MyDate {private Integer year;private Integer month;private Integer day;public String toDateString() {return year + "年" + month + "月" + day + "日";}}

全职工类 SalariedEmployee.java

@Data@NoArgsConstructorpublic class SalariedEmployee extends Employee {private double monthlySalary;public SalariedEmployee(String name, Integer number, MyDate birthday, double monthlySalary) {super(name, number, birthday);this.monthlySalary = monthlySalary;}@Overridepublic double calculateSalary() {return monthlySalary;}public String toString() {return "SalariedEmployee[" + super.toString() + "]";}}

小时工类 HourlyEmployee.java

@Data@NoArgsConstructorpublic class HourlyEmployee extends Employee {private double wage;//小时工资private int hour;//月工作小时@Overridepublic double calculateSalary() {return wage * hour;}public HourlyEmployee(String name, Integer number, MyDate birthday, double wage, int hour) {super(name, number, birthday);this.wage = wage;this.hour = hour;}public String toString() {return "HourlyEmployee[" + super.toString() + "]";}}

测试类 PayrollSystem.java

public class PayrollSystem {public static void main(String[] args) {Employee[] emps = new Employee[2];emps[0] = new SalariedEmployee("张小亮", 1001, new MyDate(1992, 1, 21), 18000);emps[1] = new HourlyEmployee("刘大地", 1002, new MyDate(1998, 4, 10), 21, 18);for (Employee emp : emps) {System.out.println(emp.toString());System.out.println("工资为:" + emp.earnings());}}}