设计模式系列漫谈之六 - 模板方法模式
在 设计模式系列漫谈之五 - 迭代器模式 中, 调用代码如下:
IListIterator iterator=new BoyList();
iterator.AddBoy(new BoyA);
iterator.AddBoy(new BoyB);
while (iterator.MoveNext())
{
IBoy boy=(IBoy)iterator.Current
if (boy.GetAge()<30 || boy.GetAge()>35)
{
iterator.RemoveBoy(boy);
}
else if (boy.GetHeight()<180)
{
iterator.RemoveBoy(boy);
}
else if (!boy.HasHouse())
{
iterator.RemoveBoy(boy);
}
else if (!boy.HasCar())
{
iterator.RemoveBoy(boy);
}
else if (!boy.HasMillion())
{
iterator.RemoveBoy(boy);
}
else
{
Console.WriteLine(boy.Name);
}
}
iterator.AddBoy(new BoyA);
iterator.AddBoy(new BoyB);
while (iterator.MoveNext())
{
IBoy boy=(IBoy)iterator.Current
if (boy.GetAge()<30 || boy.GetAge()>35)
{
iterator.RemoveBoy(boy);
}
else if (boy.GetHeight()<180)
{
iterator.RemoveBoy(boy);
}
else if (!boy.HasHouse())
{
iterator.RemoveBoy(boy);
}
else if (!boy.HasCar())
{
iterator.RemoveBoy(boy);
}
else if (!boy.HasMillion())
{
iterator.RemoveBoy(boy);
}
else
{
Console.WriteLine(boy.Name);
}
}
看到上面一大串IF...ELSE,相信大家一定会觉得非常不爽。这很显然是设计模式的大忌。其实我们可以通过模板方法模式来改进一下。
模板方法(Template Method)模式的解决方案
准备一个抽象类,将部分逻辑以具体方法以及具体构造子类的形式实现,然后声明一些抽象方法来迫使子类实现剩余的逻辑。模板方法定义两个角色:
抽象模版(AbstractClass)角色:定义了一个或多个抽象方法,具体操作由子类(具体模版)实现。然后,定义一个模版方法,并且实现这个模版方法,其逻辑的组成步骤就是之前定义的抽象操作。抽象模板必须是一个抽象类。
具体模版(ConcreteClass)角色有如下的责任:实现父类所定义的一个或多个抽象方法。
抽象模板如下:
namespace XiaoXue
{
public abstract AbstractBoy
{
public string Name;
public abstract int GetAge();
public abstract int GetHeight();
public abstract bool HasHouse();
public abstract bool HasCar();
public abstract bool HasMillion();
public bool TemplateMethod() //抽象方法
{
bool blAge=boy.GetAge()>30 && boy.GetAge()<35;
bool blHeight=boy.GetHeight()>180;
bool blHouse=boy.HasHouse();
bool blCar=boy.HasCar();
bool blMillion=boy.HasMillion();
return blAge && blHeight && blHouse && blCar && blMillion;
}
}
}
{
public abstract AbstractBoy
{
public string Name;
public abstract int GetAge();
public abstract int GetHeight();
public abstract bool HasHouse();
public abstract bool HasCar();
public abstract bool HasMillion();
public bool TemplateMethod() //抽象方法
{
bool blAge=boy.GetAge()>30 && boy.GetAge()<35;
bool blHeight=boy.GetHeight()>180;
bool blHouse=boy.HasHouse();
bool blCar=boy.HasCar();
bool blMillion=boy.HasMillion();
return blAge && blHeight && blHouse && blCar && blMillion;
}
}
}
子对象具体类如下:
namespace XiaoXue
{
public class BoyA : AbstractBoy
{
public BoyA(string name)
{
base.Name=name;
}
public override int GetAge()
{
return 25;
}
public override int GetHeight()
{
return 187;
}
public override bool HasHouse()
{
return true;
}
public override bool HasCar()
{
return false;
}
public override bool HasMillion()
{
return false;
}
}
public class BoyB : AbstractBoy
{
public BoyB(string name)
{
base.Name=name;
}
public override int GetAge()
{
return 32;
}
public override int GetHeight()
{
return 170;
}
public override bool HasHouse()
{
return true;
}
public override bool HasCar()
{
return true;
}
public override bool HasMillion()
{
return true;
}
}
}
{
public class BoyA : AbstractBoy
{
public BoyA(string name)
{
base.Name=name;
}
public override int GetAge()
{
return 25;
}
public override int GetHeight()
{
return 187;
}
public override bool HasHouse()
{
return true;
}
public override bool HasCar()
{
return false;
}
public override bool HasMillion()
{
return false;
}
}
public class BoyB : AbstractBoy
{
public BoyB(string name)
{
base.Name=name;
}
public override int GetAge()
{
return 32;
}
public override int GetHeight()
{
return 170;
}
public override bool HasHouse()
{
return true;
}
public override bool HasCar()
{
return true;
}
public override bool HasMillion()
{
return true;
}
}
}
迭代器接口和迭代器不变,请见 设计模式系列漫谈之五 - 迭代器模式
调用代码如下:
IListIterator iterator=new BoyList();
iterator.AddBoy(new BoyA("张三"));
iterator.AddBoy(new BoyB("李四");
while (iterator.MoveNext())
{
AbstractBoy boy=(AbstractBoy )iterator.Current
if (!boy.TemplateMethod())
{
iterator.RemoveBoy(boy);
}
else
{
Console.WriteLine(boy.Name);
}
}
iterator.AddBoy(new BoyA("张三"));
iterator.AddBoy(new BoyB("李四");
while (iterator.MoveNext())
{
AbstractBoy boy=(AbstractBoy )iterator.Current
if (!boy.TemplateMethod())
{
iterator.RemoveBoy(boy);
}
else
{
Console.WriteLine(boy.Name);
}
}