设计模式(二十三)—— 模板方法
模式简介
定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。TemplateMethod使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。
日常开发过程中我们经常会遇到一些行为结构大致相同,具体实现不同的场景。例如,开发一款文档读取工具,读取文档大致步骤可以抽象为打开文档->读取内容->关闭文档,但是根据文档类型不同,又需要一些具体的操作来完成这些行为(操作text文档和excel文档的方法是不同的)。这种情况下,就可以用抽象的操作定义算法骨架,在子类中重定义这些操作以提供具体的行为。
结构分析
UML类图
角色说明
- AbstractClass
抽象类。定义一系列抽象方法,具体的操作延迟到子类实现,并提供一个模板方法,定义整个算法的骨架。
- ConcreteClass
具体类。实现抽象类中的抽象方法。
工作原理
抽象类中提供模板方法定义算法骨架,将具体的操作延迟到子类中实现。
结构代码
//抽象类
public abstract class AbstractClass
{
public abstract void PrimitiveOperation1();
public abstract void PrimitiveOperation2();
public void TemplateMethod()
{
PrimitiveOperation1();
PrimitiveOperation2();
}
}
//具体类A
public class ConcreteClassA : AbstractClass
{
public override void PrimitiveOperation1()
{
Console.WriteLine("ConcreteClassA.PrimitiveOperation1");
}
public override void PrimitiveOperation2()
{
Console.WriteLine("ConcreteClassA.PrimitiveOpeartion2");
}
}
//具体类B
public class ConcreteClassB : AbstractClass
{
public override void PrimitiveOperation1()
{
Console.WriteLine("ConcreteClassB.PrimitiveOperation1");
}
public override void PrimitiveOperation2()
{
Console.WriteLine("ConcreteClassB.PrimitiveOperation2");
}
}
//客户端调用
class Program
{
static void Main(string[] args)
{
AbstractClass a = new ConcreteClassA();
a.TemplateMethod();
AbstractClass b = new ConcreteClassB();
b.TemplateMethod();
Console.ReadLine();
}
}
程序输出
示例分析
本节模拟文章开头提到的文档读取器示例,首先声明文档读取器抽象类,通过DoRead方法定义文档读取的骨架。
public abstract class DocumentReader
{
protected string _fileName;
public DocumentReader(string fileName)
{
_fileName = fileName;
}
public abstract void Open();
public abstract void Read();
public abstract void Close();
public void DoRead()
{
Open();
Read();
Close();
}
}
声明具体类TextReader和ExcelReader,分别实现抽象类中的方法。
public class TextReader : DocumentReader
{
public TextReader(string path) : base(path)
{
}
public override void Close()
{
Console.WriteLine($"Closing Text file : [{_fileName}]");
}
public override void Open()
{
Console.WriteLine($"Openning Text file : [{_fileName}]");
}
public override void Read()
{
Console.WriteLine($"Reading Text file : [{_fileName}]");
}
}
public class ExcelReader : DocumentReader
{
public ExcelReader(string path) : base(path)
{
}
public override void Close()
{
Console.WriteLine($"Closing Excel : [{_fileName}]");
}
public override void Open()
{
Console.WriteLine($"Openning Excel : [{_fileName}]");
}
public override void Read()
{
Console.WriteLine($"Reading Excel : [{_fileName}]");
}
}
客户端调用
class Program
{
static void Main(string[] args)
{
string textFileName = "abc.txt";
DocumentReader text = new TextReader(textFileName);
text.DoRead();
string excelFileName = "abc.xlsx";
DocumentReader excel = new ExcelReader(excelFileName);
excel.DoRead();
Console.ReadLine();
}
}
程序输出
适用场景
-
实现算法的不变部分,将可变的行为留给子类实现。
-
将各个类中公共的行为提取出来并集中到一个公共父类当中以避免代码重复。
-
控制子类的扩展(模板方法中已经确定各抽象方法以及调用的先后顺序)。