当我们设计一个类时,我们能明确它对外提供的某个方法的内部执行步骤,
但一些步骤,不同的子类有不同的行为时,我们该如何来设计该类?
下面以玩王者荣耀为例展开学习:
玩游戏首先需要初始化游戏,然后加载地图、加载角色、然后才能开始游戏,最后结束游戏
定义一个Game类:
public abstract class Game { public final void play () { initialize(); loadMap(); loadRole(); startPlay(); endPlay(); } /** 初始化游戏 */ protected abstract void initialize(); /** 加载地图 */ protected abstract void loadMap(); /** 加载角色 */ protected abstract void loadRole(); /** 开始游戏 */ protected abstract void startPlay(); /** 结束游戏 */ protected abstract void endPlay(); }
上面类的实现类:
public class KingGlory extends Game { @Override protected void initialize() { System.out.println("王者荣耀正在初始化,请稍后。。。"); } @Override protected void loadMap() { System.out.println("正在加载王者峡谷地图。。。"); } @Override protected void loadRole() { System.out.println("正在加载角色鲁班七号。。。"); } @Override protected void startPlay() { System.out.println("开始玩王者荣耀。。。"); } @Override protected void endPlay() { System.out.println("结束王者荣耀游戏,保存数据。。。"); } }
测试类:
public class Test { public static void main(String[] args) { Game game = new KingGlory(); game.play(); } }
一个抽象类公开定义了执行它的方法的方式/模板。它的子类可以按需要重写方法实现,但调用将以抽象类中定义的方式进行
定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。
一些方法通用,却在每一个子类都重新写了这一方法
1、有多个子类共有的方法,且逻辑相同。
2、重要的、复杂的方法,可以考虑作为模板方法
优点:
1、封装不变部分,扩展可变部分。
2、提取公共代码,便于维护。
3、行为由父类控制,子类实现。
缺点:
每一个不同的实现都需要一个子类来实现,导致类的个数增加,使得系统更加庞
类图:
涉及的角色:
对应源码:
public abstract class AbstractTemplate { public void templateMethod() { doOperation1(); doOperation2(); doOperation3(); } /** 基本方法,由子类实现 */ protected abstract void doOperation1(); /** 基本方法,由子类实现 */ protected abstract void doOperation2(); /** 基本方法,已经实现 */ private final void doOperation3(){ //do something...... } }
public class ContrateTemplate extends AbstractTemplate { @Override protected void doOperation1() { System.out.println("doOperation1......"); } @Override protected void doOperation2() { System.out.println("doOperation2......"); } }
在《西游记》中,唐僧到西天取经途中所经历的八十一难,说到底,是观音菩萨所控制的一个项目,下面以上面场景为例,写一个小例子:
取经人所经历的劫难,每一步都是菩萨控制好的:
public abstract class LearnFromPeople { public final void westernCountry() { firstHard(); secondHard(); thirdHard(); } /** 第一难 */ protected abstract void firstHard(); /** 第二难 */ protected abstract void secondHard(); /** 第三难 */ protected abstract void thirdHard(); }
唐僧去西天取经,继承了取经人这个抽象类,然后需要历经81难:
public class TangMonk extends LearnFromPeople { @Override protected void firstHard() { System.out.println("金蝉遭贬第一难"); } @Override protected void secondHard() { System.out.println("出胎几杀第二难"); } @Override protected void thirdHard() { System.out.println("满月抛江第三难"); } }
唐僧开始上路了:
public class Test { public static void main(String[] args) { LearnFromPeople people = new TangMonk(); people.westernCountry(); } }
需要注意的是,为了防止恶意的操作,模板方法上面都会加上final关键字