1 问题引入
✈️ 老套路啦!我们先来看一个需求:
有多个类,假设有三个:小学生类Pupil、中学生类MStudent、大学生类CStudent ,其中每个类都有不同的 homework() 方法,要求你统计各自完成作业需要的时间。
Tips: 在实现需求时,我们假设小学生、中学生、大学生完成作业的时间是依次增加的,将其作业的任务设置成一个方法 homework,用于完成作业并计算完成作业的时间。
🍌 参考代码:
⭐️ Pupil类:
class Pupil{ private String name = "小学生"; public String getName(){ return this.name; } // 完成作业 public void homework(){ long start = System.currentTimeMillis(); long time = 0; for (int i = 0; i < 100000; i++) { time += i; } long end = System.currentTimeMillis(); System.out.println(getName() + "完成作业用时:" + (end-start) + "h"); } }
⭐️ MStudent类:
class MStudent{ private String name = "中学生"; public String getName(){ return this.name; } // 完成作业 public void homework(){ long start = System.currentTimeMillis(); long time = 0; for (int i = 0; i < 9000000; i++) { time += i; } long end = System.currentTimeMillis(); System.out.println(getName() + "完成作业用时:" + (end-start) + "h"); } }
⭐️ CStudent类:
class CStudent{ private String name = "大学生"; public String getName(){ return this.name; } // 完成作业 public void homework(){ long start = System.currentTimeMillis(); long time = 0; for (int i = 0; i < 90000000; i++) { time += i; } long end = System.currentTimeMillis(); System.out.println(getName() + "完成作业用时:" + (end-start) + "h"); } }
⭐️ 测试类:
public class TestTemplate { public static void main(String[] args) { new Pupil().homework(); // 小学生 new MStudent().homework(); // 中学生 new CStudent().homework(); // 大学生 } }
🍎 实现结果:
小学生完成作业用时:1h
中学生完成作业用时:5h
大学生完成作业用时:26h
好啦,到这里我们已经实现了需求,但是,小伙伴们,有没有发现一个问题?我们来比较一下小学生、中学生、大学生三个类中的 homework() 方法就会发现: 代码的冗余度过高,在方法内有很多重复的步骤,代码的复用性不强! 怎么解决呢?别急继续往下看~
2 初步优化(每个类内部)
😦 我们可以从 homework() 方法中将重复的部分单独提出来,设置成一个 computingTime() 方法,用于计算作业完成所需要的时间,具体见下图(以大学生类为例,其他两个类进行一样的操作):
⭐️ Star 1: 将公共部分提取成一个方法
⭐️ Star 2: 其余部分在该方法中调用
🍌 优化后的代码如下:
public class TestTemplate { public static void main(String[] args) { new Pupil().computingTime(); // 小学生 new MStudent().computingTime(); // 中学生 new CStudent().computingTime(); // 大学生 } } class Pupil{ private String name = "小学生"; public String getName(){ return this.name; } // 计算作业完成所需要的时间 public void computingTime(){ long start = System.currentTimeMillis(); homework(); // 写作业 long end = System.currentTimeMillis(); System.out.println(getName() + "完成作业用时:" + (end-start) + "h"); } // 完成作业 public void homework(){ long time = 0; for (int i = 0; i < 100000; i++) { time += i; } } } class MStudent{ private String name = "中学生"; public String getName(){ return this.name; } // 计算作业完成所需要的时间 public void computingTime(){ long start = System.currentTimeMillis(); homework(); // 写作业 long end = System.currentTimeMillis(); System.out.println(getName() + "完成作业用时:" + (end-start) + "h"); } // 完成作业 public void homework(){ long time = 0; for (int i = 0; i < 9000000; i++) { time += i; } } } class CStudent{ private String name = "大学生"; public String getName(){ return this.name; } // 计算作业完成所需要的时间 public void computingTime(){ long start = System.currentTimeMillis(); homework(); // 写作业 long end = System.currentTimeMillis(); System.out.println(getName() + "完成作业用时:" + (end-start) + "h"); } // 完成作业 public void homework(){ long time = 0; for (int i = 0; i < 90000000; i++) { time += i; } } }
🍑 现在,我们已经成功将方法中的公共部分给提取出来,单独设置成了 computingTime() 方法,但是,很快我们又发现了问题:一共有三个类,每个类都需要提取一次,设置出一个单独的方法,还是过于繁琐,需要进一步优化,我们接着往下看。
3 抽象模板设计
😎 既然重复,我们为何不 尝试将重复的部分提取到一个模板类里,让这三个类继承 呢?这样每个类都不需要声明该方法,就可以使用啦!具体如下图:
🍑 在这里,我们将三个类中共有的computingTime() 方法提取到 Template类作为模板,让子类继承。并且,将三个类中不同的部分 homework类 在父类中抽象,子类实现。在实际调用中,由于动态绑定机制,使用的则是 new 创建的对象所绑定的方法,先是子类,若子类不存在该方法再访问父类,这点在之前的文章讲过,这里直接上传送门哈!
❤️ 【JavaSE】面向对象之多态、向上转型与向下转型
具体方式如下:
🍌 优化后的完整代码:
public class TestTemplate { public static void main(String[] args) { new Pupil().computingTime(); // 小学生 new MStudent().computingTime(); // 中学生 new CStudent().computingTime(); // 大学生 } } // 模板类 abstract class Template{ private String name; public String getName(){ return this.name; } // 计算作业完成所需要的时间 public void computingTime(){ long start = System.currentTimeMillis(); homework(); // 写作业 long end = System.currentTimeMillis(); System.out.println(getName() + "完成作业用时:" + (end-start) + "h"); } abstract void homework(); } class Pupil extends Template{ private String name = "小学生"; public String getName(){ return this.name; } // 完成作业 public void homework(){ long time = 0; for (int i = 0; i < 100000; i++) { time += i; } } } class MStudent extends Template{ private String name = "中学生"; public String getName(){ return this.name; } // 完成作业 public void homework(){ long time = 0; for (int i = 0; i < 9000000; i++) { time += i; } } } class CStudent extends Template{ private String name = "大学生"; public String getName(){ return this.name; } // 完成作业 public void homework(){ long time = 0; for (int i = 0; i < 90000000; i++) { time += i; } } }
🍎 实现结果:
小学生完成作业用时:1h
中学生完成作业用时:4h
大学生完成作业用时:26h