Template Method(模板方法)
1、意图:
定义一个操作中的算法骨架,而将一些步骤的具体实现延迟到子类中。TemplateMethod 使得子类可以不改变一个算法的结构(步骤)即可重定义该算法的某些特定步骤的具体实现。
2、模式中的角色
抽象类(AbstractClass):实现了模板方法,定义了算法的骨架。
具体类(ConcreteClass):实现抽象类中的抽象方法,已完成完整的算法。
3、模板方法类图
4、实例:
去饭馆吃饭,一般分可分为3个步骤,点菜、吃饭、买单,而每个人去吃都是这个步骤,不同得是点的菜、吃饭花的时间、花的钱不一样而已,所以可以将点菜、吃饭、买单这3个步骤分别写成3个方法,而把这3个方法放到一个模板方法里面。具体实现如下:
AbstractClass:
- /**
- * 餐馆吃饭抽象类
- *
- * @author xieke
- * @since 15.7.28
- */
- public abstract class Eat
- {
- // 所点菜的集合
- protected List<Menu> list;
- /**
- * 吃饭模板方法
- * @param list
- * @return
- */
- public double eat(List<Menu> list)
- {
- // 1.点菜
- this.dianCai(list);
- // 2.吃饭
- this.chiFan();
- // 3.买单
- return this.maiDan();
- }
- /**
- * 点菜
- * @param list
- */
- public void dianCai(List<Menu> list)
- {
- this.list = list;
- }
- /**
- * 吃饭
- */
- public abstract void chiFan();
- /**
- * 买单
- * @return
- */
- public double maiDan()
- {
- double money = 0.0;
- for (Menu menu : list)
- {
- money += menu.getMoney();
- }
- return money;
- }
- }
ConcreteClass:
- public class MeEat extends Eat
- {
- @Override
- public void chiFan()
- {
- System.out.println("我吃饭花了30分钟......");
- for(Menu menu : this.list){
- System.out.println(menu.toString());
- }
- }
- }
菜单实体类:
- public class Menu
- {
- private String name;
- private double money;
- public String getName()
- {
- return name;
- }
- public void setName(String name)
- {
- this.name = name;
- }
- public double getMoney()
- {
- return money;
- }
- public void setMoney(double money)
- {
- this.money = money;
- }
- public Menu(String name, double money)
- {
- this.name = name;
- this.money = money;
- }
- @Override
- public String toString()
- {
- return name + ":" + money;
- }
- }
测试类:
- public class MainClass
- {
- public static void main(String[] args)
- {
- Eat eat = new MeEat();
- List<Menu> list = new ArrayList<Menu>();
- list.add(new Menu("水煮牛肉", 30.0));
- list.add(new Menu("麻婆豆腐", 10.0));
- System.out.println("本次吃饭共花费:"+eat.eat(list));
- }
- }
5、模式总结
5.1 优点
5.1.1 模板方法模式通过把不变的行为搬移到超类,去除了子类中的重复代码。
5.1.2 子类实现算法的某些细节,有助于算法的扩展。
5.1.3 通过一个父类调用子类实现的操作,通过子类扩展增加新的行为,符合“开放-封闭原则”。
5.2 缺点
5.2.1 每个不同的实现都需要定义一个子类,这会导致类的个数的增加,设计更加抽象。
5.3 适用场景
5.1 在某些类的算法中,用了相同的方法,造成代码的重复。
5.2 控制子类扩展,子类必须遵守算法规则。