10.1模板方法模式定义
在一个方法中定义一个算法的框架,而将一些步骤延迟到子类中。模板方法可以使得子类在不改变算法结构的情况下,重新定义算法中的某些步骤。
10.2模板方法模式UML类图:
模式方法的定义:void TemplateMethod()。模式方法不能声明成virtual是因为当然不允许子类改变算法的框架。
10.3应用场景:
模块方法在定义整个算法的框架时特别有用,它甚至可以说是用得最多的设计模式之一。当我们某一个算法有公共步骤可能被需要子类用到,而某些步骤是必需由子类实现的,这时我们就可以利用模板方法模式。例如我们制作咖啡的算法,冲水这个动作是所有咖啡都要用到的,而放调料这个算法是由不同的咖啡(子类)来决定的,因为不同的咖啡放的是不同的调料,这时我们就可以将咖啡制作定义成一个模块方法,其中调用抽象方法放调料和非抽象方法冲水。
10.4模板方法模式分析与实现(c#描述):
//最简单的模板方法示例
namespace SimpleTemplateMethod
{
//苹果类,里面包含模块方法。
public abstract class Apple
{
public void Prepare()//模板方法,一系列方法的组合。
{
this.Wash();
this.Cut();
}
public void Wash()//洗苹果的动作对所有苹果来说都一样,因此这里设为非抽象方法,被所有子类所共用。
{
Console.WriteLine("把苹果洗了,呵呵。");
}
public abstract void Cut();//抽象方法,由子类决定如何切苹果。
//这里又是让子类决定,是不是跟工厂方法的让子类决定很相似呢?呵呵。其实,工厂方法就是模板方法的一个特例。因为工厂方法让子类决定的是类的创建,而模板方法让子类决定的是算法的步骤。
}
//红苹果,其切法为每个苹果切成2块。
public class RedApple : Apple
{
public override void Cut()
{
Console.WriteLine("把苹果切成2块。");
}
}
//黄苹果,其切法为每个苹果切成4块。
public class YellowApple : Apple
{
public override void Cut()
{
Console.WriteLine("把苹果切成4块。");
}
}
//调用类
public class SimpleTemplateMethod_Test
{
public static void Do()
{
Apple lobj_Apple = new RedApple();
lobj_Apple.Prepare();//红苹果的切法是每个苹果切成2块。
lobj_Apple = new YellowApple();
lobj_Apple.Prepare();//黄苹果的切法是每个苹果切成4块。
}
}
}
//带钩子的模板方法示例。钩子在这里是用于决定算法流程的一个方法。
namespace TemplateMethodWithHook
{
public abstract class Apple
{
public void Prepare()
{
this.Wash();
if (this.CanCut())//这里由于由子类决定是否可以进行切割,所以相当于可以由子类决定是否改变算法流程。
{
this.Cut();
}
}
public void Wash ()
{
Console.WriteLine("把苹果洗了,呵呵。");
}
public abstract void Cut();
//钩子,子类通过对其控制可以改变算法流程。
public virtual bool CanCut()
{
return true;//默认为需要对苹果进行切分。
}
}
//红苹果,其切法为每个苹果切成2块。
public class RedApple : Apple
{
public override void Cut()
{
Console.WriteLine("把苹果切成2块。");
}
}
//黄苹果,其切法为每个苹果切成4块。
public class YellowApple : Apple
{
public override void Cut()
{
Console.WriteLine("把苹果切成4块。");
}
public override bool CanCut()//黄苹果不允许将苹果进行切分。
{
return false;
}
}
//调用类
public class TemplateMethodWithHook_Test
{
public static void Do()
{
Apple lobj_Apple = new RedApple();
lobj_Apple.Prepare();//红苹果的切法是每个苹果切成2块。
lobj_Apple = new YellowApple();
lobj_Apple.Prepare();//红苹果的切法是每个苹果切成4块,但由于黄苹果使用的钩子说不切了,所以这里不对苹果进行切分。
}
}
}
namespace TemplateMethodInCSharp
{
public class Bird : IComparable
{
private string _Name;
public string Name
{
get { return _Name; }
set { _Name = value; }
}
private int _Weight;
public Bird(string astg_Name,int aint_Weight)
{
this._Name = astg_Name;
this._Weight = aint_Weight;
}
public int CompareTo(object obj)//CompareTo为模板方法中的某个步骤,这里我们定义以鸟的排序规则:根据重量排序,重量较轻的顺序在前,重量较重的顺序在后。
{
if (this._Weight > ((Bird)obj)._Weight) return 1;
else if (this._Weight == ((Bird)obj)._Weight) return 0;
else return -1;
}
}
//调用类
public class TemplateMethodInCSharp_Test
{
public static void Do()
{
//下面我们利用Array的Sort模板方法对Bird进行排序。
Bird[] arr_Birds = new Bird[] { new Bird("Andy",3), new Bird("Cherry",2), new Bird("Tom",5) };
Array.Sort(arr_Birds);
for (int lint_LoopCount = 0; lint_LoopCount < arr_Birds.Length; lint_LoopCount++)
{
Console.WriteLine(arr_Birds[lint_LoopCount].Name);
}
//模板方法说的是利用继承让子类实现父类中的抽象算法步骤,这里没有用到继承为什么也是模板方法呢?请注意,模板方法的实现形态可以多种多样的,这种算是模板方法的变体吧。
}
}
}
这个模式用来创建一个算法的模板。什么是模板?实际上模板就是一个方法,这个方法将算法定义成一组步骤,其中的任何步骤都要以是抽象的,由子类进行实现,这样就要以保证算法的整体框架不变,然后由子类提供部分实现。