模板方法设计模式
抽象类体现的就是一种模板模式的设计,抽象类作为多个子类的通用模板,子类在抽象类的基础上进行拓展、改造,但子类总体上会保留抽象类的行为方式。
模板方法解决的问题
当功能内部一部分实现是确定的,一部分实现是不确定的。这时可以把不确定的部分暴露出去,让子类去实现。
换句话说,在软件开发中实现一个算法时,整体的步骤很固定、通用,这些步骤已经在父类中写好了。但是某些部分不确定,不确定的部分可以抽象出来,供不同子类实现。这就是一种模板模式。
代码举例
我们创建一个父类Template,该父类我们创建一个spendTime的方法,想计算出某一段代码的运行时间。整体的步骤就是:
①获取当前的时间
②代码(就是你想测试运行时间的代码)
③获取当前的时间
④两次获取的时间相减,就得出②号代码运行的时间了
但是!问题在于,②号到底要测试什么代码,有好几种情况,我们不确定,可是①②④的步骤我们是百分之一万确定的。所以就将②号需要测试的代码,在父类Template中,给封装成一个抽象方法,让子类去重写,再通过多态来调用。
public class TemplateTest {
public static void main(String[] args) {
//此处为多态
Template sub = new SubTemplate();
sub.spendTime();
//分界线
System.out.println("**************************");
//此处为多态
Template sub_1 = new SubTemplate_1();
sub_1.spendTime();
}
}
abstract class Template{
//计算某段代码执行所需要花费的时间
public void spendTime() {
//获取当前时间
long start = System.currentTimeMillis();
//被测试代码
code();
//获取当前时间
long end = System.currentTimeMillis();
//输出代码运行时间
System.out.println("花费的时间为:" + (end - start));
}
//由于code内具体是什么代码,不确定,此处将其设为抽象方法,交给子类去具体实现
public abstract void code();
}
class SubTemplate extends Template{
//重写父类code方法,计算一千以内的质数
public void code() {
for(int i = 2;i < 1000;i++ ) {
boolean isFlag = true;
for(int j = 2;j < Math.sqrt(i);j++) {
if(i % j == 0) {
isFlag = false;
break;
}
}
if(isFlag) {
System.out.println(i);
}
}
}
}
class SubTemplate_1 extends Template{
//重写父类code方法,计算五百以内的质数
public void code() {
for(int i = 2;i < 500;i++ ) {
boolean isFlag = true;
for(int j = 2;j < Math.sqrt(i);j++) {
if(i % j == 0) {
isFlag = false;
break;
}
}
if(isFlag) {
System.out.println(i);
}
}
}
}
一句话概括设计模式:模板方法
父类Template就是一个模板,这个模板单独拿出来没有任何意义,只有根据不同的情况去实例化不同的子类,子类重写父类的空白的抽象方法,两者结合,才有了意义。
总结
由上述代码可以总结,我们不确定要测试哪段代码的执行时间,我们就在父类中创建一个抽象方法,然后在子类中去具体实现该方法,然后通过多态来实现访问子类中被重写的方法,就可以实现测试不同的代码运行的时间。
此处只是举了一个简单的例子,模板方法还有很多用途。
读者可能存在的疑惑
①父类中的public abstract void code();为什么要声明为抽象的,不声明抽象,我子类也可以重写该方法,实现相同的效果。
答:如果父类该方法不声明为抽象方法,该方法就得写成public void code(){ },并且存在万一子类没有重写code方法,然后你又调用了spendTime()方法,那么这样子做毫无意义。此处将其声明为抽象方法,就会强制要求你子类中必须重写code方法,尽量的减少了调用了一个空的方法体的可能,如果你子类重写还是重写空的方法体,那这样子做也没意义呀。
②父类Template和子类code都不声明为抽象,也可以实现上述情况代码
答:此处回答同上,如果父类Template和子类code都不是抽象的,那么就可以直接创建一个父类的实例,调用里面的方法,但是code方法又是空的,这样子做毫无意义,声明为抽象就是不希望你们创建父类的实例,父类仅仅就是作为一个模板而存在。