返回

7.模板方法模式

在一个操作方法中定义算法的流程,其中某些步骤由子类完成。模板方法模式让子类在不变更原有算法流程的情况下,还能够重新定义其中的步骤。

模板方法模式

在一个操作方法中定义算法的流程,其中某些步骤由子类完成。模板方法模式让子类在不变更原有算法流程的情况下,还能够重新定义其中的步骤。

模板方法的定义

从上述来看,模板方法模式包含以下两个概念:

  1. 定义一个算法的流程,即是很明确地定义算法的每一个步骤,并写在父类的方法中,而每一个步骤都可以是一个方法的调用。
  2. 某些步骤由子类完成,为什么父类不自己完成,却要由子类去实现内?
    • 定义算法的流程中,某些步骤需要由执行时“当下的环境”来决定。
    • 定义算法时,针对每一个步骤都提供了预设的解决方案,但优势会出现“更改好的解决方法”,此时就需要让这个更好的解决方法,能够在原有的架构中被使用。

参与者说明如下:

  • AbstractClass(算法定义类)
    • 定义算法架构的类。
    • 可以在某个操作方法(TemplateMethod)中定义完整的流程。
    • 定义流程中会调用到方法(PrimitiveOpration),这些方法将由子类重新实现。
  • ConcreteClass(算法步骤的实现类)
    • 重新定义父类中定义的方法,并可以按照子类的执行情况反映步骤实际的内容。

具体实现

// 定義完整演算法各步驟及執行順序
public abstract class AbstractClass
{
   public void TemplateMethod()
   {
      PrimitiveOperation1();
      PrimitiveOperation2();
   }
   protected abstract void PrimitiveOperation1();
   protected abstract void PrimitiveOperation2();
}

// 實作演算法各步驟
public class ConcreteClassA : AbstractClass
{
   protected override void PrimitiveOperation1()
   {
      Debug.Log("ConcreteClassA.PrimitiveOperation1");
   }
   protected override void PrimitiveOperation2()
   {
      Debug.Log("ConcreteClassA.PrimitiveOperation2");
   }
}

// 實作演算法各步驟
public class ConcreteClassB : AbstractClass
{
   protected override void PrimitiveOperation1()
   {
      Debug.Log("ConcreteClassB.PrimitiveOperation1");
   }
   protected override void PrimitiveOperation2()
   {
      Debug.Log("ConcreteClassB.PrimitiveOperation2");
   }
}

//测试方法
public class TemplateMethodTest : MonoBehaviour 
{
	void Start () {
		UnitTest();	
	}
	
	void UnitTest () 
	{
		AbstractClass theClass = new ConcreteClassA();
		theClass.TemplateMethod();

		theClass = new ConcreteClassB();
		theClass.TemplateMethod();	
	}
}

何时使用模板方法模式

如果程序设计师发现更新一段程序代码之后,还有另一端程序代码也使用相同的“演算流程”,且实现的内容不太一样,那么这两段程序代码就可以用模板方法模式加以重写。

模板方法模式的应用

  • 奇幻类角色扮演游戏(RPG),对于游戏角色要施展一个法术时,会有许多特定的检查条件,如魔力是否足够、是否还在冷却时间内,对象是否在法术施展范围内等。如果这些检查条件会按照施展法术的类型而有所不同,那么就可以使用模板方法模式将检查流程固定下来,真正检查的功能则交给各法术子类去实现。另外,一个法术的施展流程和各种计算也可以将流程固定下来,细节交给各法术子类去实现。
  • 在线游戏的角色登录,也可以使用模板方法模式将登录流程固定下来,例如:显示登陆画面、选择登录方法、输入账号密码、向Server请求登录等,然后让登录功能的子类去重新实现其中的步骤。另外,也可以实现不同的登录流程样板来对应不同的登录方式。