C#设计模式之9:模板方法

时间:2023-03-09 18:05:40
C#设计模式之9:模板方法

模板方法

模板方法是一个方法,定义了算法的步骤,并允许子类为一个或多个步骤提供实现。

本例中用冲泡咖啡和茶的例子来说明:

C#设计模式之9:模板方法

上图说明了冲泡咖啡和茶的步骤,可以看出冲泡咖啡和茶的步骤差不多,很相似,先来看看没有应用模板方法的代码:

C#设计模式之9:模板方法

Tea的代码类似,就不放了。他们的一个不好的地方在于算法散落在了各个类中,还有一点是重复的代码。

public abstract class CaffeineBeverage//设计一个抽象类,将算法进行封装
{
public void BoilWater()
{
Console.WriteLine("boil water");
} public void PourInCup()
{
Console.WriteLine("pour in cup");
} public void PrepareRecipe()//封装算法,这个就是模板方法。
{
BoilWater();
Brew();
PourInCup();
AddCondiment();
}
public abstract void Brew();//具体的实现要到子类中实现
public abstract void AddCondiment();//具体的实现要到子类中实现
}
public class TeaLogic: CaffeineBeverage
{
public override void Brew()
{
Console.WriteLine("brew tea");
} public override void AddCondiment()
{
Console.WriteLine("add some lemon");
}
}
public class CoffeLogin:CaffeineBeverage
{
public override void Brew()
{
Console.WriteLine("brew coffe...");
} public override void AddCondiment()
{
Console.WriteLine("add some milk and sugar...");
}
}

模板方法定义了一个算法步骤,并允许子类其中一个或多个实现提供步骤。

模板方法的定义:在一个方法中定义算法的骨架,而将一些步骤延迟到子类中。模板方法可以在子类不改变算法结构的情况下,重新定义算法中的某些步骤。

C#设计模式之9:模板方法

同时,AbstractClass内部定义一个钩子方法——一个虚方法,可以在子类中决定是否重写,达到挂钩的目的。钩子的存在,可以让子类有能力对算法的不同点进行挂钩,要不要挂钩,由子类自行决定。

//在模板方法中应用钩子
public abstract class AnotherKindOfCoffeineBeverage
{
public void BoilWater()
{
Console.WriteLine("boil water");
}
public void PourInCup()
{
Console.WriteLine("pour in cup..");
}
public virtual bool CustomerWantCondiment()//虚方法。。表示一个钩子
{
return true;
}
public abstract void Brew();
public abstract void AddCondiment();
public void PrepareRecipe()
{
BoilWater();
Brew();
if (CustomerWantCondiment())
{
AddCondiment();
}
PourInCup();
}
}
//应用钩子方法的一个场景
public class AnotherKindOfTea : AnotherKindOfCoffeineBeverage
{
public override bool CustomerWantCondiment()
{
return GetCustomerInput().Equals("y");
}
public override void Brew()
{
Console.WriteLine("dropping coffe through filter..");
}
public override void AddCondiment()
{
Console.WriteLine("add some condiment..");
}
private string GetCustomerInput()
{
Console.WriteLine("would you like some lemon with your tea?(y/n)");
var input = Console.ReadLine();
return input?.ToLower();
}
}

关于钩子,由这么一个原则:当你必须提供模板方法中的某个步骤时,就在基类中做成抽象方法,如果这个步骤是可选的,就做成虚方法,钩子。

钩子可以让子类实现算法中的可选部分,或者在钩子对于子类的实现不那么重要的时候,子类可以对此钩子置之不理。钩子的另一个用法,是让子类能够有机会对模板方法中某些即将发生的步骤做出反应。钩子也可以让子类有能力为其抽象类做一些决定。

最重要的一点:抽象类中的某些方法是可选的,对于这些可选的方法,就做成钩子,而不是做成抽象方法,这样就可以让子类的负荷减轻。

新的设计原则:好莱坞设计原则——不要调用(打电话给)我们,我会调用(打电话给)你。

C#设计模式之9:模板方法

C#设计模式之9:模板方法

好莱坞原则和模板方法

他们两个的联系还算是比较明显:当我们设计模板方法时,我们告诉子类,“不要调用我们,我们会调用你”。

C#设计模式之9:模板方法

好莱坞原则和依赖倒置原则之间的关系:

C#设计模式之9:模板方法