定义
定义一个操作中算法的框架,而将一些步骤延迟到子类中。模板方法模式使得子类不改变一个算法的结构即可重定义该算法的某些特定步骤。
模板方法模式是一种基于继承的代码复用技术,它是一种类行为型模式。
模板方法模式是结构最简单的行为型设计模式,在其结构中只存在父类与子类之间的继承关系。通过使用模板方法模式,可以将一些复杂流程的实现步骤封装在一系列基本方法中,在抽象父类中提供一个称为模板方法的方法来定义这些基本方法的执行次序,而通过其子类来覆盖某些步骤,从而使得相同的算法框架可以有不同的执行结果。模板方法模式提供了一个模板方法来定义算法框架,而某些具体步骤的实现可以在其子类中完成。
举例
如请客吃饭,无论吃什么,过程都是:点单->吃东西->买单。但是返回的结果可以不同,吃饭或者吃面条
还有像写信的目标:开头是收件人名称,中间内容,其次是写信人名称,时间
结构
实现
/// <summary>
/// AbstractClass是抽象类,其实也就是一抽象模板,定义并实现了一个模版方法。
/// 这个模版方法一般是一个具体方法,它给出了一个顶级逻辑的骨架,而逻辑的组成步骤在相应的抽象操作中,推迟到子类实现。
/// 顶级逻辑也有可能调用一些具体方法。
/// </summary>
abstract class AbstractClass
{
//抽象行为,放到子类实现
public abstract void PrimitiveOperation1();
public abstract void PrimitiveOperation2();
/// <summary>
/// 模板方法,给出了逻辑的骨架,而逻辑的组成是一些相应的抽象操作,它们都推迟到子类实现
/// </summary>
public void TemplateMethod()
{
PrimitiveOperation1();
PrimitiveOperation2();
Console.WriteLine("");
}
}
/// <summary>
/// ConcreteClass,实现父类所定义的一个或多个抽象方法。每一个AbstractClass都可以有任意多个ConcreteClass与之对应,
/// 而每一个ConcreteClass 都可以给出这些抽象方法(也就是顶级逻辑的组成步骤)的不同实现,从而使得顶级逻辑的实现各不相同。
/// </summary>
class ConcreteClassA : AbstractClass
{
public override void PrimitiveOperation1()
{
//与ConcreteClassB不同的方法实现
Console.WriteLine("具体类A方法1实现");
}
public override void PrimitiveOperation2()
{
Console.WriteLine("具体类A方法2实现");
}
}
class ConcreteClassB : AbstractClass
{
public override void PrimitiveOperation1()
{
//与ConcreteClassA不同的方法实现
Console.WriteLine("具体类A方法1实现");
}
public override void PrimitiveOperation2()
{
Console.WriteLine("具体类A方法2实现");
}
}
class Program
{
static void Main(string[] args)
{
AbstractClass c;
c = new ConcreteClassA();
c.TemplateMethod();
c = new ConcreteClassB();
c.TemplateMethod();
}
}
优点
- (1)在父类中形式化地定义一个算法,而由它的子类来实现细节的处理,在子类实现详细的处理算法时并不会改变算法中步骤的执行次序。
- (2)模板方法模式是一种代码复用技术,在类库设计中尤为重要﹐它提取了类库中的公共行为,将公共行为放在父类中,而通过其子类来实现不同的行为,它鼓励用户恰当地使用继承来实现代码复用。
- (3)模板方法模式可实现一-种反向控制结构,通过子类覆盖父类的钩子方法来决定某一特定步骤是否需要执行。
- (4)在模板方法模式中可以通过子类来覆盖父类的基本方法,不同的子类可以提供基本方法的不同实现,更换和增加新的子类很方便,符合单一职责原则和开闭原则。
缺点
模板方法模式需要为每一个基本方法的不同实现提供一个子类,如果父类中可变的基本方法太多,将会导致类的个数增加,系统会更加庞大,设计也会更加抽象﹐此时,可结合桥接模式来进行设计。
适用环境
- (1)对一些复杂的算法进行分割,将其算法中固定不变的部分设计为模板方法和父类具体方法,而将一些可以改变的细节由其子类来实现,即一次性实现一个算法的不变部分,并将可变的行为留给子类来实现。
- (2)各子类中公共的行为应被提取出来,并集中到一个公共父类中,以避免代码重复。
- (3)需要通过子类来决定父类算法中的某个步骤是否执行,实现子类对父类的反向控制。