23、C#设计模式 - 模板方法模式

模板方法模式(Template Method Pattern)

模板方法模式属于行为型模式,定义一个模板结构,将具体内容延迟到子类去实现。

在不改变模板结构的前提下在子类中重新定义模板中的内容。

角色:

1、 抽象类(AbstractClass);

实现了模板方法,定义了算法的框架;

2、 具体类(ConcreteClass);

实现抽象类中的抽象方法,以完成完整的算法。

 

命名空间TemplateMethod中包含DataSource数据源抽象类,其中有一些实例方法、抽象方法和钩子方法(IsNotJson),ShowChart方法使用数据源显示一个图表。本示例使用这个案例来向大家讲解模板方法模式的实现要领。

namespace TemplateMethod
public abstract class DataSource {

    protected abstract void FetchSource();

    protected virtual bool IsNotJson() {
        return true;
    }

    protected abstract void Convert2Json();

    protected abstract void ShowData();

    public void ShowChart() {
        FetchSource();
        if (IsNotJson()) {
            Convert2Json();
        }
        ShowData();
        Console.WriteLine("----------------------------------");
    }

}

数据源抽象基类DataSouce,包含取数据FetchSource方法,是否是Json数据IsNotJson方法,转化成Json格式Convert2Json方法,最后是显示数据图表ShowChart方法。

C#开发笔记之03-为什么选择IsNotXXX方法而不是IsXXX方法?

public class TextData : DataSource {

    protected override void FetchSource() {
        Console.WriteLine($"Fetch data from {this.ToString()}!");
    }

    protected override void Convert2Json() {
        Console.WriteLine($"Convert {this.ToString()} to Json!");
    }

    protected override void ShowData() {
        Console.WriteLine($"Show data in chart control!");
    }

}

文本数据源TextData类。

public class BinaryData : DataSource {

    protected override void FetchSource() {
        Console.WriteLine($"Fetch data from {this.ToString()}!");
    }

    protected override void Convert2Json() {
        Console.WriteLine($"Convert {this.ToString()} to Json!");
    }

    protected override void ShowData() {
        Console.WriteLine($"Show data in chart control!");
    }

}

二进制数据源BinaryData类。

public class JsonData : DataSource {

    protected override void FetchSource() {
        Console.WriteLine($"Fetch data from {this.ToString()}!");
    }

    protected override bool IsNotJson() {
        return false;
    }

    protected override void Convert2Json() {
        Console.WriteLine("This line can not be reached!");
        Console.WriteLine("There's no need to convert data!");
    }

    protected override void ShowData() {
        Console.WriteLine($"Show data in chart control!");
    }

}

Json数据源JsonData类。

public class CloudData : DataSource {

    protected override void FetchSource() {
        Console.WriteLine($"Fetch data from {this.ToString()}!");
    }

    protected override void Convert2Json() {
        Console.WriteLine($"Convert {this.ToString()} to Json!");
    }

    protected override void ShowData() {
        Console.WriteLine($"Show data in chart control!");
    }

}

云数据源CloudData类。

public class Program {

    private static DataSource _dataSource = null;

    public static void Main(string[] args) {
        _dataSource = new TextData();
        _dataSource.ShowChart();

        _dataSource = new BinaryData();
        _dataSource.ShowChart();

        _dataSource = new JsonData();
        _dataSource.ShowChart();

        _dataSource = new CloudData();
        _dataSource.ShowChart();

        Console.ReadKey();
    }

}

以上是调用方的代码,以下是这个案例的输出结果:

Fetch data from TemplateMethod.TextData!
Convert TemplateMethod.TextData to Json!
Show data in chart control!
----------------------------------
Fetch data from TemplateMethod.BinaryData!
Convert TemplateMethod.BinaryData to Json!
Show data in chart control!
----------------------------------
Fetch data from TemplateMethod.JsonData!
Show data in chart control!
----------------------------------
Fetch data from TemplateMethod.CloudData!
Convert TemplateMethod.CloudData to Json!
Show data in chart control!
----------------------------------

优点:

1、 提高代码复用性,可以将相同部分的代码放在抽象的父类中;
2、 提高了拓展性,将不同的代码放入不同的子类中,通过对子类的扩展增加新的行为;
3、 实现了反向控制,通过一个父类调用其子类的操作,通过对子类的扩展增加新的行为;

缺点:

1、 引入了抽象类,每一个不同的实现都需要一个子类来实现,导致类的个数增加,从而增加了系统实现的复杂度;

使用场景:

1、 一次性实现一个算法的不变的部分,并将可变的行为留给子类来实现;
2、 各子类中公共的行为应被提取出来并集中到一个公共父类中以避免代码重复;