【愚公系列】2023年10月 二十三种设计模式(二十二)-模板方法模式(Template Method Pattern)

举报
愚公搬代码 发表于 2021/12/05 00:38:48 2021/12/05
【摘要】 设计模式(Design Pattern)是软件开发领域的宝贵经验,是多人反复借鉴和广泛应用的代码设计指导。它们是一系列经过分类和归纳的代码组织方法,旨在实现可重用性、可维护性和可理解性。使用设计模式,我们能够编写高质量的代码,使其更易于他人理解,并提供了代码可靠性的保证。

🏆 作者简介,愚公搬代码
🏆《头衔》:华为云特约编辑,华为云云享专家,华为开发者专家,华为产品云测专家,CSDN博客专家,阿里云专家博主,腾讯云优秀博主,掘金优秀博主,51CTO博客专家等。
🏆《近期荣誉》:2022年CSDN博客之星TOP2,2022年华为云十佳博主等。
🏆《博客内容》:.NET、Java、Python、Go、Node、前端、IOS、Android、鸿蒙、Linux、物联网、网络安全、大数据、人工智能、U3D游戏、小程序等相关领域知识。
🏆🎉欢迎 👍点赞✍评论⭐收藏

🚀前言

设计模式(Design Pattern)是软件开发领域的宝贵经验,是多人反复借鉴和广泛应用的代码设计指导。它们是一系列经过分类和归纳的代码组织方法,旨在实现可重用性、可维护性和可理解性。使用设计模式,我们能够编写高质量的代码,使其更易于他人理解,并提供了代码可靠性的保证。

毫无疑问,设计模式对个人、团队和整个系统都带来了显著的益处。它们将代码开发提升到工程化水平,为软件工程构建提供了坚实的基础,就如同大厦的一块块精巧的砖石一样。在项目中明智地应用设计模式可以完美地解决各种复杂问题。每种设计模式都有相应的原理和最佳实践,它们描述了我们日常开发中不断遇到的问题,以及这些问题的核心解决方法。正是因为这种实用性和通用性,设计模式才能在软件开发中广泛地得以应用。设计模式是构建稳健、可扩展和可维护软件的关键工具,为开发者们提供了解决问题的智慧和指导。

🚀一、模板方法模式(Template Method Pattern)

模板方法模式(Template Method Pattern)是一种行为设计模式,它定义了一个算法的框架,并将某些步骤延迟到子类中实现,以便子类可以重新定义算法的某些步骤而不改变算法的结构。

模板方法模式主要解决的问题是在不改变算法框架的情况下,允许子类重新定义算法的某些步骤。模板方法模式通常由一个抽象类和多个具体子类组成。抽象类中定义算法的框架,具体子类实现算法的具体步骤。

模板方法模式有以下几个角色:

  1. 抽象类(Abstract Class):定义了算法的框架,其中某些步骤由具体子类实现。

  2. 具体子类(Concrete Class):实现抽象类中定义的某些步骤,以便重新定义算法的行为。

模板方法模式的优点:

  1. 提高代码复用性。将通用代码放在抽象类中实现,具体子类只需实现自己的特殊代码,从而减少了重复代码。

  2. 提高代码可扩展性。由于具体子类可以重新定义算法的某些步骤,从而增加算法的灵活性和可扩展性。

  3. 提高代码的安全性。把重要的逻辑放在抽象类中实现,避免了具体子类乱改重要逻辑的风险。

模板方法模式的缺点:

  1. 由于在抽象类中定义了算法框架,因此增加了系统的抽象性和理解难度。

  2. 如果算法框架需要频繁变动,则模板方法模式不太适用。

在实际开发中,模板方法模式常用于框架设计中,例如在Spring框架中,JdbcTemplate就是模板方法模式的典型应用。同时,模板方法模式也可以用于日志框架、数据库访问框架、网络通信框架等领域。

🚀二、使用步骤

🔎1.角色

🦋1.1 抽象类(Abstract Class)

模板方法模式(Template Method Pattern)是一种常见的行为型设计模式,它在面向对象编程中使用抽象类(Abstract Class)的概念来实现。

抽象类的概念和作用在模板方法模式中是非常关键的:

  1. 抽象类概念:抽象类是一种不能被实例化的类,它定义了一组抽象方法和具体方法。抽象方法是在抽象类中声明但没有具体实现的方法,而具体方法则有默认实现。抽象类通常用于定义一个通用的算法框架,其中的某些步骤由子类来实现。

  2. 作用

    • 定义算法框架:抽象类用于定义一个算法或操作的框架,其中包含了一系列步骤,这些步骤可以是抽象的,由子类来实现。
    • 强制子类实现:抽象类中的抽象方法要求子类必须提供具体的实现,从而确保了特定步骤的定制化。
    • 代码复用:抽象类中的具体方法可以被多个子类共享,从而提高了代码的复用性。
    • 封装不变部分:抽象类将算法框架中不变的部分封装在具体方法中,保持了一致性,而将可变的部分留给子类实现,以满足不同需求。

在模板方法模式中,抽象类通常包含一个模板方法,该方法定义了算法的结构,包括一系列的步骤调用,其中的某些步骤由抽象方法或子类实现。这样,子类可以继承抽象类,并根据具体需求实现特定的步骤,同时保持了整体算法的一致性和可维护性。这种方式有助于降低代码的耦合度,提高了代码的可扩展

🦋1.2 具体类(Concrete Class)

模板方法模式(Template Method Pattern)中,具体类(Concrete Class)是指实际用于实现模板方法的子类。具体类扮演着重要的角色,具体化了抽象模板中的抽象方法,从而实现了特定的行为。

具体类的概念和作用如下:

  1. 概念:具体类是继承自抽象类的子类,它们提供了对抽象方法的具体实现,以适应特定的需求。在模板方法模式中,可以有多个具体类,每个具体类代表了不同的实现方式。

  2. 作用

    • 实现抽象方法:具体类必须实现在抽象类中声明的所有抽象方法。这些方法代表了在模板方法中特定步骤的实际行为。
    • 定制化行为:每个具体类可以根据自身的需求,为抽象方法提供具体的实现,从而定制化算法的某些部分。
    • 提供具体内容:具体类中的方法实现具体的功能,将抽象方法具体化,从而在整个模板方法中完成具体的业务逻辑。
    • 多态性:使用具体类实现多态性,允许不同的具体类在相同的抽象模板下执行不同的操作,而客户端代码可以通过抽象类来操作这些具体类,实现松耦合。

具体类的作用在于充实了模板方法的具体细节,使得模板方法模式能够灵活应对不同情境下的需求,同时保持了共同的模板结构。这种模式有助于降低代码的重复性,增加了代码的可维护性和可扩展性,因为可以轻松地添加新的具体类以扩展功能。

🔎2.示例

在这里插入图片描述

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

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方法。

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.优点

模板方法模式(Template Method Pattern)有许多优点,使其成为一种常用的设计模式之一。以下是模板方法模式的一些主要优点:

  1. 代码复用:模板方法模式通过将共同的行为移到抽象父类中,可以在不同的具体子类中重复使用这些代码。这降低了代码的重复性,提高了代码的复用性。

  2. 封装不变部分:抽象父类中的模板方法定义了算法的骨架,其中包含了不变的部分。这些不变的部分被封装在抽象父类中,确保了一致性,减少了代码的冗余。

  3. 可扩展性:模板方法模式通过具体子类来实现特定的步骤,允许系统在不修改整体算法结构的情况下,添加新的子类以扩展功能。这增强了系统的可扩展性。

  4. 高内聚低耦合:抽象父类中的模板方法将相似的操作聚合在一起,减少了不必要的耦合,提高了代码的内聚性。具体子类之间的耦合性也较低,因为它们独立实现自己的具体行为。

  5. 提高了代码的可维护性:将具体实现从抽象方法中分离出来,使得每个子类都相对简单,易于理解和维护。这有助于降低系统的维护成本。

  6. 促进了代码的一致性:模板方法模式确保了在不同的子类中,相同的步骤以相同的方式执行,从而提高了代码的一致性和可预测性。

  7. 支持反向控制:模板方法模式允许子类对抽象父类中的模板方法进行反向控制,通过实现不同的具体方法来改变父类中的行为。

  8. 易于理解:模板方法模式使整个算法的结构更加清晰,因为它将算法的关键步骤抽象出来,使得代码的逻辑更易于理解。

模板方法模式提供了一种有效的方式来实现代码重用、提高可维护性和可扩展性,并在系统中建立了一种有组织的算法框架。这使得它在许多领域和场景中都非常有

🔎2.缺点

尽管模板方法模式(Template Method Pattern)具有许多优点,但也存在一些缺点和限制,需要在使用时考虑:

  1. 限制了部分灵活性:模板方法模式在一定程度上限制了子类的自由度。因为它规定了算法的框架,子类必须按照这个框架来实现具体的步骤,这可能不适用于所有情况。

  2. 不适合复杂算法变种:如果算法的变种非常复杂,模板方法模式可能会导致类的层次结构变得复杂和难以维护。在这种情况下,可能需要考虑其他设计模式来更灵活地处理不同的变种。

  3. 困难的子类维护:当存在多个具体子类时,维护这些子类可能会变得复杂,尤其是在添加新的具体子类或修改现有的子类时。这可能导致类的数量增加,增加了系统的复杂性。

  4. 可能违反单一责任原则:如果不小心,模板方法模式可能导致将太多的责任放在抽象父类中,使其变得过于庞大,违反了单一责任原则。这可能导致难以理解和维护的代码。

  5. 不容易适应变化:如果算法中的某个步骤需要在不同的情况下具有不同的行为,模板方法模式可能不够灵活,需要修改抽象父类或引入条件语句来处理这种情况。

  6. 可能引入性能开销:在模板方法中,每个步骤都是一个方法调用,这可能会引入一定的性能开销,尤其是在算法非常复杂的情况下。

  7. 不适合所有情况:模板方法模式并不适用于所有类型的问题。它更适用于那些具有相似算法结构但具体实现不同的情况。

模板方法模式是一种有用的设计模式,但它不是解决所有问题的银弹。在使用时,需要仔细权衡其优点和缺点,确保它适合特定的情境和需求。有时候,其他设计模式可能更适合处理复杂的算法变种或更灵活的情况。

🔎3.使用场景

模板方法模式(Template Method Pattern)适用于以下一些常见场景和情况:

  1. 算法框架固定,但具体步骤可变:当一个算法的基本框架在不同情况下保持不变,但其中一些具体步骤的实现可能有所不同时,模板方法模式非常有用。它允许将不变部分抽象到父类中,而将可变部分延迟到子类中实现。

  2. 避免代码重复:如果多个类中存在相似的代码,可以使用模板方法模式来避免重复实现这些代码。将共同的行为移到抽象父类中,减少了冗余代码。

  3. 定义算法的骨架:模板方法模式帮助你定义一个算法的基本骨架,使得整个算法结构更清晰。这对于其他开发人员理解和维护代码非常有帮助。

  4. 在框架设计中使用:在框架或库的设计中,模板方法模式常用于定义一组标准接口和抽象类,以供开发者进行扩展和自定义。这种情况下,具体的扩展点留给了开发者,而框架提供了整体结构。

  5. 实现不同层次的抽象:模板方法模式可以用于多层次的抽象,其中一个抽象父类定义了算法的高级骨架,而具体子类可以进一步细化这个算法。

  6. 支持代码的一致性和可维护性:当需要确保在不同子类中相同的步骤以相同的方式执行时,模板方法模式非常有用。它提供了一种方式来强制一致性,并提高了代码的可维护性。

  7. 扩展性:模板方法模式允许轻松地添加新的具体子类,以扩展功能。这在需要不断增加新功能的系统中非常有用。

模板方法模式适用于那些需要定义算法框架,但允许不同部分有不同实现的情况。它有助于提高代码的可重用性、可维护性和可扩展性,并确保一致性的代码执行。因此,在需要满足这些需求的软件设计中,模板方法模式是一个有力的工具。


🚀感谢:给读者的一封信

亲爱的读者,

我在这篇文章中投入了大量的心血和时间,希望为您提供有价值的内容。这篇文章包含了深入的研究和个人经验,我相信这些信息对您非常有帮助。

如果您觉得这篇文章对您有所帮助,我诚恳地请求您考虑赞赏1元钱的支持。这个金额不会对您的财务状况造成负担,但它会对我继续创作高质量的内容产生积极的影响。

我之所以写这篇文章,是因为我热爱分享有用的知识和见解。您的支持将帮助我继续这个使命,也鼓励我花更多的时间和精力创作更多有价值的内容。

如果您愿意支持我的创作,请扫描下面二维码,您的支持将不胜感激。同时,如果您有任何反馈或建议,也欢迎与我分享。

在这里插入图片描述

再次感谢您的阅读和支持!

最诚挚的问候, “愚公搬代码”

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。