3 Template Method模式

3.1 Template Method模式

在父类中定义处理流程的框架,在子类中具体实现的模式称为Template Method模式。

3.2 示例程序

示例程序的类图

image.png

类的一览表

名字 说明
AbstractDisplay 只实现了display方法的抽象类
CharDisplay 实现了open print close方法的类
StringDisplay 实现了open print close方法的类
Main 测试程序

AbstractDisplay
是一个抽象类,只实现了display方法。调用其他方法,实际处理被交给了子类。

  1. public abstract class AbstractDisplay { // 抽象类AbstractDisplay
  2. public abstract void open(); // 交给子类去实现的抽象方法(1) open
  3. public abstract void print(); // 交给子类去实现的抽象方法(2) print
  4. public abstract void close(); // 交给子类去实现的抽象方法(3) close
  5. public final void display() { // 本抽象类中实现的display方法
  6. open(); // 首先打开…
  7. for (int i = 0; i < 5; i++) { // 循环调用5次print
  8. print();
  9. }
  10. close(); // …最后关闭。这就是display方法所实现的功能
  11. }
  12. }
  1. public class CharDisplay extends AbstractDisplay { // CharDisplay是AbstractDisplay的子类
  2. private char ch; // 需要显示的字符
  3. public CharDisplay(char ch) { // 构造函数中接收的字符被
  4. this.ch = ch; // 保存在字段中
  5. }
  6. @Override
  7. public void open() { // 在父类中是抽象方法,此处重写该方法
  8. System.out.print("<<"); // 显示开始字符"<<"
  9. }
  10. @Override
  11. public void print() { // 同样地重写print方法。该方法会在display中被重复调用
  12. System.out.print(ch); // 显示保存在字段ch中的字符
  13. }
  14. @Override
  15. public void close() { // 同样地重写close方法
  16. System.out.println(">>"); // 显示结束字符">>"
  17. }
  18. }
  19. public class StringDisplay extends AbstractDisplay { // StringDisplay也是AbstractDisplay的子类
  20. private String string; // 需要显示的字符串
  21. private int width; // 以字节为单位计算出的字符串长度
  22. public StringDisplay(String string) { // 构造函数中接收的字符串被
  23. this.string = string; // 保存在字段中
  24. this.width = string.getBytes().length; // 同时将字符串的字节长度也保存在字段中,以供后面使用
  25. }
  26. @Override
  27. public void open() { // 重写的open方法
  28. printLine(); // 调用该类的printLine方法画线
  29. }
  30. @Override
  31. public void print() { // print方法
  32. System.out.println("|" + string + "|"); // 给保存在字段中的字符串前后分别加上"|"并显示出来
  33. }
  34. @Override
  35. public void close() { // close方法
  36. printLine(); // 与open方法一样,调用printLine方法画线
  37. }
  38. private void printLine() { // 被open和close方法调用。由于可见性是private,因此只能在本类中被调用
  39. System.out.print("+"); // 显示表示方框的角的"+"
  40. for (int i = 0; i < width; i++) { // 显示width个"-"
  41. System.out.print("-"); // 组成方框的边框
  42. }
  43. System.out.println("+"); // /显示表示方框的角的"+"
  44. }
  45. }

3.3 Template Method模式中的角色

在Template Method模式中的角色。

  • AbstractClass(抽象类) 该角色不仅负责实现模板方法,还负责声明在模板方法中使用到的抽象方法。这些抽象方法由子类ConcreteClass角色负责实现。
  • ConcreteClass(具体类) 该角色负责具体AbstractClass角色中定义的抽象方法。

image.png

3.4 扩展思路的要点

可以使逻辑处理通用化
使用模板模式的优点是,由于再父类的模板方法中编写了算法,因此无需子类中在编写算法。

父类和子类之间的协作
在模板模式中,父类和子类是密切联系、共同工作的。因此,在子类中实现父类中声明的抽象方法时,必须要理解理解抽象方法被调用的时机。在看不到父类源码的情况下,想要编写出子类是非常困难的。

父类与子类的一致性
无论在父类类型的变量中保存哪个子类的实例,程序都可以正常工作,这种原则称为里氏替换原则(LSP)。

3.6 延伸阅读:类的层次与抽象类

父类对子类的要求
在理解类的层次时,通常是站在子类的角度进行思考的。也就说,很容易着眼与以下几点。

  • 在子类中可以使用父类中定义的方法。
  • 可以通过在子类中增加方法以实现新的功能。
  • 在子类中重写父类的方法可以改变程序的行为

站在父类的角度思考。在父类中,我们声明了抽象方法,而将方法的实现交给了子类。换而言之,就程序而言,声明抽象是希望达到以下目的。

  • 期待子类去实现抽象方法
  • 要求子类去实现抽象方法

也就是说,子类具有实现在父类中所声明的抽象方法的责任,这种责任被称为“子类责任”。

4 Factory Method模式(将实例的生成交给子类)

4.1 Factory Method

在Factory Method模式中,父类决定实例的生成方式,但并不决定所要生成具体的类,具体的处理全部交给子类负责。这样就可以将生成实例的框架和实际负责生成实例的类解耦。

4.2 示例程序

image.png


  1. Product类和Factory类属于framework包。这两个类组成了生成实例的框架。<br />IDCard类和IDCardFactory类负责实际加工处理,它们属于idcard包。
  • 生成实例的框架(framework包)
  • 加工处理(idcard包)


  1. public abstract class Factory {
  2. public final Product create(String owner) {
  3. Product p = createProduct(owner);
  4. registerProduct(p);
  5. return p;
  6. }
  7. protected abstract Product createProduct(String owner);
  8. protected abstract void registerProduct(Product product);
  9. }
  10. public abstract class Product {
  11. public abstract void use();
  12. }
  1. public class IDCardFactory extends Factory {
  2. private List owners = new ArrayList();
  3. @Override
  4. protected Product createProduct(String owner) {
  5. return new IDCard(owner);
  6. }
  7. @Override
  8. protected void registerProduct(Product product) {
  9. owners.add(((IDCard) product).getOwner());
  10. }
  11. public List getOwners() {
  12. return owners;
  13. }
  14. }
  15. public class IDCard extends Product {
  16. private String owner;
  17. IDCard(String owner) {
  18. System.out.println("制作" + owner + "的ID卡。");
  19. this.owner = owner;
  20. }
  21. @Override
  22. public void use() {
  23. System.out.println("使用" + owner + "的ID卡。");
  24. }
  25. public String getOwner() {
  26. return owner;
  27. }
  28. }

4.3 Factory Method模式中的角色

image.png

类图中的角色

  • Product(产品):Product角色属于框架这一方,是一个抽象类。它定义了Factory Method模式中生成的那些实例所持有的接口,但具体的处理交给ConcreteProduct角色决定。
  • Creator(创建者):Creator角色属于框架一方,它是负责生成Product角色的抽象类,但具体的处理则由子类ConcreteCreator角色决定
  • ConcreteProduct(具体的产品):属于具体加工一方,它决定了具体的产品。
  • ConcreteCreator(具体的创建者):属于具体加工这一方。负责生成具体的产品。