【愚公系列】2023年10月 二十三种设计模式(二十二)-模板方法模式(Template Method Pattern)
🏆 作者简介,愚公搬代码
🏆《头衔》:华为云特约编辑,华为云云享专家,华为开发者专家,华为产品云测专家,CSDN博客专家,阿里云专家博主,腾讯云优秀博主,掘金优秀博主,51CTO博客专家等。
🏆《近期荣誉》:2022年CSDN博客之星TOP2,2022年华为云十佳博主等。
🏆《博客内容》:.NET、Java、Python、Go、Node、前端、IOS、Android、鸿蒙、Linux、物联网、网络安全、大数据、人工智能、U3D游戏、小程序等相关领域知识。
🏆🎉欢迎 👍点赞✍评论⭐收藏
🚀前言
设计模式(Design Pattern)是软件开发领域的宝贵经验,是多人反复借鉴和广泛应用的代码设计指导。它们是一系列经过分类和归纳的代码组织方法,旨在实现可重用性、可维护性和可理解性。使用设计模式,我们能够编写高质量的代码,使其更易于他人理解,并提供了代码可靠性的保证。
毫无疑问,设计模式对个人、团队和整个系统都带来了显著的益处。它们将代码开发提升到工程化水平,为软件工程构建提供了坚实的基础,就如同大厦的一块块精巧的砖石一样。在项目中明智地应用设计模式可以完美地解决各种复杂问题。每种设计模式都有相应的原理和最佳实践,它们描述了我们日常开发中不断遇到的问题,以及这些问题的核心解决方法。正是因为这种实用性和通用性,设计模式才能在软件开发中广泛地得以应用。设计模式是构建稳健、可扩展和可维护软件的关键工具,为开发者们提供了解决问题的智慧和指导。
🚀一、模板方法模式(Template Method Pattern)
模板方法模式(Template Method Pattern)是一种行为设计模式,它定义了一个算法的框架,并将某些步骤延迟到子类中实现,以便子类可以重新定义算法的某些步骤而不改变算法的结构。
模板方法模式主要解决的问题是在不改变算法框架的情况下,允许子类重新定义算法的某些步骤。模板方法模式通常由一个抽象类和多个具体子类组成。抽象类中定义算法的框架,具体子类实现算法的具体步骤。
模板方法模式有以下几个角色:
抽象类(Abstract Class):定义了算法的框架,其中某些步骤由具体子类实现。
具体子类(Concrete Class):实现抽象类中定义的某些步骤,以便重新定义算法的行为。
模板方法模式的优点:
提高代码复用性。将通用代码放在抽象类中实现,具体子类只需实现自己的特殊代码,从而减少了重复代码。
提高代码可扩展性。由于具体子类可以重新定义算法的某些步骤,从而增加算法的灵活性和可扩展性。
提高代码的安全性。把重要的逻辑放在抽象类中实现,避免了具体子类乱改重要逻辑的风险。
模板方法模式的缺点:
由于在抽象类中定义了算法框架,因此增加了系统的抽象性和理解难度。
如果算法框架需要频繁变动,则模板方法模式不太适用。
在实际开发中,模板方法模式常用于框架设计中,例如在Spring框架中,JdbcTemplate就是模板方法模式的典型应用。同时,模板方法模式也可以用于日志框架、数据库访问框架、网络通信框架等领域。
🚀二、使用步骤
🔎1.角色
🦋1.1 抽象类(Abstract Class)
模板方法模式(Template Method Pattern)是一种常见的行为型设计模式,它在面向对象编程中使用抽象类(Abstract Class)的概念来实现。
抽象类的概念和作用在模板方法模式中是非常关键的:
抽象类概念:抽象类是一种不能被实例化的类,它定义了一组抽象方法和具体方法。抽象方法是在抽象类中声明但没有具体实现的方法,而具体方法则有默认实现。抽象类通常用于定义一个通用的算法框架,其中的某些步骤由子类来实现。
作用:
- 定义算法框架:抽象类用于定义一个算法或操作的框架,其中包含了一系列步骤,这些步骤可以是抽象的,由子类来实现。
- 强制子类实现:抽象类中的抽象方法要求子类必须提供具体的实现,从而确保了特定步骤的定制化。
- 代码复用:抽象类中的具体方法可以被多个子类共享,从而提高了代码的复用性。
- 封装不变部分:抽象类将算法框架中不变的部分封装在具体方法中,保持了一致性,而将可变的部分留给子类实现,以满足不同需求。
在模板方法模式中,抽象类通常包含一个模板方法,该方法定义了算法的结构,包括一系列的步骤调用,其中的某些步骤由抽象方法或子类实现。这样,子类可以继承抽象类,并根据具体需求实现特定的步骤,同时保持了整体算法的一致性和可维护性。这种方式有助于降低代码的耦合度,提高了代码的可扩展
🦋1.2 具体类(Concrete Class)
模板方法模式(Template Method Pattern)中,具体类(Concrete Class)是指实际用于实现模板方法的子类。具体类扮演着重要的角色,具体化了抽象模板中的抽象方法,从而实现了特定的行为。
具体类的概念和作用如下:
概念:具体类是继承自抽象类的子类,它们提供了对抽象方法的具体实现,以适应特定的需求。在模板方法模式中,可以有多个具体类,每个具体类代表了不同的实现方式。
作用:
- 实现抽象方法:具体类必须实现在抽象类中声明的所有抽象方法。这些方法代表了在模板方法中特定步骤的实际行为。
- 定制化行为:每个具体类可以根据自身的需求,为抽象方法提供具体的实现,从而定制化算法的某些部分。
- 提供具体内容:具体类中的方法实现具体的功能,将抽象方法具体化,从而在整个模板方法中完成具体的业务逻辑。
- 多态性:使用具体类实现多态性,允许不同的具体类在相同的抽象模板下执行不同的操作,而客户端代码可以通过抽象类来操作这些具体类,实现松耦合。
具体类的作用在于充实了模板方法的具体细节,使得模板方法模式能够灵活应对不同情境下的需求,同时保持了共同的模板结构。这种模式有助于降低代码的重复性,增加了代码的可维护性和可扩展性,因为可以轻松地添加新的具体类以扩展功能。
🔎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)有许多优点,使其成为一种常用的设计模式之一。以下是模板方法模式的一些主要优点:
代码复用:模板方法模式通过将共同的行为移到抽象父类中,可以在不同的具体子类中重复使用这些代码。这降低了代码的重复性,提高了代码的复用性。
封装不变部分:抽象父类中的模板方法定义了算法的骨架,其中包含了不变的部分。这些不变的部分被封装在抽象父类中,确保了一致性,减少了代码的冗余。
可扩展性:模板方法模式通过具体子类来实现特定的步骤,允许系统在不修改整体算法结构的情况下,添加新的子类以扩展功能。这增强了系统的可扩展性。
高内聚低耦合:抽象父类中的模板方法将相似的操作聚合在一起,减少了不必要的耦合,提高了代码的内聚性。具体子类之间的耦合性也较低,因为它们独立实现自己的具体行为。
提高了代码的可维护性:将具体实现从抽象方法中分离出来,使得每个子类都相对简单,易于理解和维护。这有助于降低系统的维护成本。
促进了代码的一致性:模板方法模式确保了在不同的子类中,相同的步骤以相同的方式执行,从而提高了代码的一致性和可预测性。
支持反向控制:模板方法模式允许子类对抽象父类中的模板方法进行反向控制,通过实现不同的具体方法来改变父类中的行为。
易于理解:模板方法模式使整个算法的结构更加清晰,因为它将算法的关键步骤抽象出来,使得代码的逻辑更易于理解。
模板方法模式提供了一种有效的方式来实现代码重用、提高可维护性和可扩展性,并在系统中建立了一种有组织的算法框架。这使得它在许多领域和场景中都非常有
🔎2.缺点
尽管模板方法模式(Template Method Pattern)具有许多优点,但也存在一些缺点和限制,需要在使用时考虑:
限制了部分灵活性:模板方法模式在一定程度上限制了子类的自由度。因为它规定了算法的框架,子类必须按照这个框架来实现具体的步骤,这可能不适用于所有情况。
不适合复杂算法变种:如果算法的变种非常复杂,模板方法模式可能会导致类的层次结构变得复杂和难以维护。在这种情况下,可能需要考虑其他设计模式来更灵活地处理不同的变种。
困难的子类维护:当存在多个具体子类时,维护这些子类可能会变得复杂,尤其是在添加新的具体子类或修改现有的子类时。这可能导致类的数量增加,增加了系统的复杂性。
可能违反单一责任原则:如果不小心,模板方法模式可能导致将太多的责任放在抽象父类中,使其变得过于庞大,违反了单一责任原则。这可能导致难以理解和维护的代码。
不容易适应变化:如果算法中的某个步骤需要在不同的情况下具有不同的行为,模板方法模式可能不够灵活,需要修改抽象父类或引入条件语句来处理这种情况。
可能引入性能开销:在模板方法中,每个步骤都是一个方法调用,这可能会引入一定的性能开销,尤其是在算法非常复杂的情况下。
不适合所有情况:模板方法模式并不适用于所有类型的问题。它更适用于那些具有相似算法结构但具体实现不同的情况。
模板方法模式是一种有用的设计模式,但它不是解决所有问题的银弹。在使用时,需要仔细权衡其优点和缺点,确保它适合特定的情境和需求。有时候,其他设计模式可能更适合处理复杂的算法变种或更灵活的情况。
🔎3.使用场景
模板方法模式(Template Method Pattern)适用于以下一些常见场景和情况:
算法框架固定,但具体步骤可变:当一个算法的基本框架在不同情况下保持不变,但其中一些具体步骤的实现可能有所不同时,模板方法模式非常有用。它允许将不变部分抽象到父类中,而将可变部分延迟到子类中实现。
避免代码重复:如果多个类中存在相似的代码,可以使用模板方法模式来避免重复实现这些代码。将共同的行为移到抽象父类中,减少了冗余代码。
定义算法的骨架:模板方法模式帮助你定义一个算法的基本骨架,使得整个算法结构更清晰。这对于其他开发人员理解和维护代码非常有帮助。
在框架设计中使用:在框架或库的设计中,模板方法模式常用于定义一组标准接口和抽象类,以供开发者进行扩展和自定义。这种情况下,具体的扩展点留给了开发者,而框架提供了整体结构。
实现不同层次的抽象:模板方法模式可以用于多层次的抽象,其中一个抽象父类定义了算法的高级骨架,而具体子类可以进一步细化这个算法。
支持代码的一致性和可维护性:当需要确保在不同子类中相同的步骤以相同的方式执行时,模板方法模式非常有用。它提供了一种方式来强制一致性,并提高了代码的可维护性。
扩展性:模板方法模式允许轻松地添加新的具体子类,以扩展功能。这在需要不断增加新功能的系统中非常有用。
模板方法模式适用于那些需要定义算法框架,但允许不同部分有不同实现的情况。它有助于提高代码的可重用性、可维护性和可扩展性,并确保一致性的代码执行。因此,在需要满足这些需求的软件设计中,模板方法模式是一个有力的工具。
🚀感谢:给读者的一封信
亲爱的读者,
我在这篇文章中投入了大量的心血和时间,希望为您提供有价值的内容。这篇文章包含了深入的研究和个人经验,我相信这些信息对您非常有帮助。
如果您觉得这篇文章对您有所帮助,我诚恳地请求您考虑赞赏1元钱的支持。这个金额不会对您的财务状况造成负担,但它会对我继续创作高质量的内容产生积极的影响。
我之所以写这篇文章,是因为我热爱分享有用的知识和见解。您的支持将帮助我继续这个使命,也鼓励我花更多的时间和精力创作更多有价值的内容。
如果您愿意支持我的创作,请扫描下面二维码,您的支持将不胜感激。同时,如果您有任何反馈或建议,也欢迎与我分享。
再次感谢您的阅读和支持!
最诚挚的问候, “愚公搬代码”
- 点赞
- 收藏
- 关注作者
评论(0)