【设计模式】模板模式策略模式
发布时间:2026/10/7 21:20:11 作者:尧图编辑部 阅读量:1,286

最Low方式假如现在有3只企鹅都喜欢“吃饭睡觉打豆豆”public class littlePenguin { public void everyDay() { System.out.println(吃饭); System.out.println(睡觉); System.out.println(用小翅膀打豆豆); } } public class middlePenguin { public void everyDay() { System.out.println(吃饭); System.out.println(睡觉); System.out.println(用圆圆的肚子打豆豆); } } public class bigPenguin { public void everyDay() { System.out.println(吃饭); System.out.println(睡觉); System.out.println(拿鸡毛掸子打豆豆); } } public class test { public static void main(String[] args) { System.out.println(littlePenguin:); littlePenguin penguin_1 new littlePenguin(); penguin_1.everyDay(); System.out.println(middlePenguin:); middlePenguin penguin_2 new middlePenguin(); penguin_2.everyDay(); System.out.println(bigPenguin:); bigPenguin penguin_3 new bigPenguin(); penguin_3.everyDay(); } }看一下执行结果littlePenguin: 吃饭 睡觉 用小翅膀打豆豆 middlePenguin: 吃饭 睡觉 用圆圆的肚子打豆豆 bigPenguin: 吃饭 睡觉 拿鸡毛掸子打豆豆这种方式是大家写代码时最容易使用的方式上手简单也容易理解目前看项目中陈旧的代码经常能找到它们的影子下面我们看怎么一步步将其进行重构。常规方式“吃饭睡觉打豆豆”其实都是独立的行为为了不相互影响比如吃饭时突然睡着了或者睡觉时不好好睡居然急着跑去打豆豆开个玩笑哈~~我们可以通过函数简单进行封装public class littlePenguin { public void eating() { System.out.println(吃饭); } public void sleeping() { System.out.println(睡觉); } public void beating() { System.out.println(用小翅膀打豆豆); } } public class middlePenguin { public void eating() { System.out.println(吃饭); } public void sleeping() { System.out.println(睡觉); } public void beating() { System.out.println(用圆圆的肚子打豆豆); } } // bigPenguin相同省略... public class test { public static void main(String[] args) { System.out.println(littlePenguin:); littlePenguin penguin_1 new littlePenguin(); penguin_1.eating(); penguin_1.sleeping(); penguin_1.beating(); // 下同省略... } }这样看起来是不是要稍微清晰一些呢工作过一段时间的同学可能会采用这种实现方式我们有没有更优雅的实现方式呢模板模式在模板模式Template Pattern中一个抽象类公开定义了执行它的方法的方式/模板。它的子类可以按需要重写方法实现但调用将以抽象类中定义的方式进行。这种类型的设计模式属于行为型模式。这3只企鹅由于每天吃的都一样睡觉也都是站着睡但是打豆豆的方式却不同所以我们可以将“吃饭睡觉打豆豆”抽象出来因为“吃饭睡觉”都一样所以我们可以直接实现出来但是他们“打豆豆”的方式不同所以封装成抽象方法需要每个企鹅单独去实现“打豆豆”的方式。最后再新增一个方法everyDay()固定每天的执行流程public abstract class penguin { public void eating() { System.out.println(吃饭); } public void sleeping() { System.out.println(睡觉); } public abstract void beating(); public void everyDay() { this.eating(); this.sleeping(); this.beating(); } }每只企鹅单独实现自己“打豆豆”的方式public class littlePenguin extends penguin { Override public void beating() { System.out.println(用小翅膀打豆豆); } } public class middlePenguin extends penguin { Override public void beating() { System.out.println(用圆圆的肚子打豆豆); } } public class bigPenguin extends penguin { Override public void beating() { System.out.println(拿鸡毛掸子打豆豆); } }最后看调用方式public class test { public static void main(String[] args) { System.out.println(littlePenguin:); littlePenguin penguin1 new littlePenguin(); penguin1.everyDay(); System.out.println(middlePenguin:); middlePenguin penguin2 new middlePenguin(); penguin2.everyDay(); System.out.println(bigPenguin:); bigPenguin penguin3 new bigPenguin(); penguin3.everyDay(); } }“楼哥你这代码看的费劲能给我画一个UML图么”“嗯其实画图挺麻烦的谁让楼哥是暖男呢那我就学着给大家画一个”策略模式在策略模式Strategy Pattern中一个类的行为或其算法可以在运行时更改。这种类型的设计模式属于行为型模式。在策略模式中我们创建表示各种策略的对象和一个行为随着策略对象改变而改变的 context 对象。策略对象改变 context 对象的执行算法。我们还是先抽象出3个企鹅的行为public abstract class penguin { public void eating() { System.out.println(吃饭); } public void sleeping() { System.out.println(睡觉); } public abstract void beating(); }每只企鹅单独实现自己“打豆豆”的方式public class littlePenguin extends penguin { Override public void beating() { System.out.println(用小翅膀打豆豆); } } public class middlePenguin extends penguin { Override public void beating() { System.out.println(用圆圆的肚子打豆豆); } } public class bigPenguin extends penguin { Override public void beating() { System.out.println(拿鸡毛掸子打豆豆); } }这里就是策略模式的重点我们再看一下策略模式的定义“我们创建表示各种策略的对象和一个行为随着策略对象改变而改变的context对象”那么该contex对象如下public class behaviorContext { private penguin _penguin; public behaviorContext(penguin newPenguin) { _penguin newPenguin; } public void setPenguin(penguin newPenguin) { _penguin newPenguin; } public void everyDay() { _penguin.eating(); _penguin.sleeping(); _penguin.beating(); } }最后看调用方式public class test { public static void main(String[] args) { behaviorContext behavior new behaviorContext(new littlePenguin()); behavior.everyDay(); behavior.setPenguin(new middlePenguin()); behavior.everyDay(); behavior.setPenguin(new bigPenguin()); behavior.everyDay(); } }我们可以通过给behaviorContext传递不同的对象然后来约定everyDay()的调用方式。其实我这个示例有点把策略模式讲复杂了因为纯粹的策略模式3个企鹅只有beating()方法不同所以可以把beating()理解为不同的算法即可之所以引入everyDay()是因为实际的项目场景中会经常这么使用也就是把这个变化的算法beating()包装到具体的执行流程里面所以策略模式就看起来没有那么直观但是核心思想是一样的。再强调一下下面的UML图是使用了策略模式因为我想结合具体的业务场景去讲如果大家想去看最简版的策略模式那就没有everyDay的封装只有对beating执行的策略变更这个可以看一下菜鸟教程。模板模式 vs 策略模式我在选择模板模式和策略模式时发现两者都可以完全满足我的需求然后我到网上查阅了很多资料希望能找到两种模式在技术选择时能确定告诉我哪些情况需要选择哪种模式说来惭愧到现在我都没有找到因为网上只告诉我两种实现姿势的区别但是没有说明如何具体选型下面我就把我收集的资料觉得比较核心的部分列出来给大家一些参考。有人请向我解释模板方法模式和策略模式之间有什么区别据我可以告诉他们是99相同 – 唯一的区别是模板方法模式具有抽象类作为基类而战略类使用由每个具体战略类实现的接口。然而就客户而言他们的消费方式完全一样 – 这是正确的吗两者的主要区别在于具体algorithm的select。使用Template方法模式时通过子类化模板在编译时发生。每个子类通过实现模板的抽象方法提供了一个不同的具体algorithm。当客户端调用模板的外部接口的方法时模板根据需要调用其抽象方法其内部接口来调用algorithm。相比之下 策略模式允许在运行时通过遏制来selectalgorithm。具体algorithm是通过单独的类或函数实现的这些类或函数作为parameter passing给构造函数或构造方法。为此参数select哪种algorithm会根据程序的状态或inputdynamic变化。综上所述模板方法模式通过子类化 编译时间algorithmselect策略模式通过遏制 运行时algorithmselect上面是完全摘抄网上的区别说明只看到实现姿势的区别但是如果通过这个就能指导我去选型我觉得还不够下面这个可能会讲的更具体一点相似策略和模板方法模式都可以用来满足开闭原则使得软件模块在不改变代码的情况下易于扩展。两种模式都表示通用function与该function的详细实现的分离。不过它们所提供的粒度有一些差异。差异在策略中客户和策略之间的耦合更加松散而在模板方法中两个模块耦合得更紧密。在策略中虽然抽象类也可以根据具体情况而使用但大多使用一个接口而不使用具体类而在Template方法中大多使用抽象类或具体类不使用接口。在Strategy模式中类的整体行为一般用接口表示另一方面Template方法用于减less代码重复样板代码在基本框架或抽象类中定义。在Template Method中甚至可以有一个具有默认实现的具体类。简而言之您可以在策略模式中更改整个策略algorithm但是在Template模式中只有一些事情发生变化algorithm的一部分而其余事件保持不变。在Template Method中不变步骤是在一个抽象基类中实现的而变体步骤要么是默认的实现要么根本就没有实现。在Template方法中组件devise器强制执行algorithm所需的步骤和步骤的sorting但允许组件客户端扩展或replace某些步骤。看到上面的总结感觉还是没有解答我的疑问最后再引用一段网上的区别解读模板模式它基于inheritance。定义不能被子类改变的algorithm的骨架。只有某些操作可以在子类中重写。父类完全控制algorithm 仅将具体的步骤与具体的类进行区分。绑定是在编译时完成的。策略模式它基于授权/组成。它通过修改方法的行为来改变对象的内容。它用于在algorithm族之间切换。它在运行时通过在运行时用其他algorithm完全replace一个algorithm来改变对象的行为。绑定在运行时完成。对于有强迫症的我没有找到问题的根源总感觉哪里不对劲我就说一下我对于两者区别的理解吧。说实话两种设计模式我也就看到在实现姿势上有所区别至于说的策略模式要定义统一接口模板模式不这样做等我不太赞同因为我有时也会给模板模式定义一个通用接口。然后也有人说策略模式需要定义一堆对象模板模式就不需要如果有10个不同的企鹅模板模式不也是需要定义10个不同的企鹅类然后再专门针对特定的方法去实现么所以说这两种设计模式我感觉还没有到非此即彼的划分我就是怎么爽就怎么用比如我不需要固定的执行流程比如只去打豆豆只需要对一个方法做具体抽象我愿意选择策略模式因为这个我感觉会让我需要使用的对象更清晰一些。如果我有固定的执行流程比如“吃饭、睡觉、打豆豆”我更愿意使用模板方法可能是代码看多了也看习惯了更愿意用模板方法去规范代码固定的执行流程。当然我也可以将两者结合起来使用比如我们可以用模板方法去实现这3只企鹅但是对于middlePenguin可能有分为企鹅少年A、企鹅少年B、企鹅少年C他们都喜欢隔壁的企鹅妹妹但是喜欢的方式不同有暗恋的有直接表白的还有霸道总裁的我可以用策略模式去指定他们对企鹅妹妹的表达方式。哥就是这么任性自己怎么用的爽就怎么来~~实际场景任何模式都需要结合实际的场景来讲才能更清晰。这两个模式可以在你之前做过的项目中只要稍微留意一下应该会发现它们其实是大量存在的比如很多框架代码里面有很多固定的执行流程有些逻辑是可以采用默认处理的方式有些逻辑需要下游自己去实现然后有些逻辑还需要提前预留钩子比如在执行process()流程时可能需要进行preProcess()的操作那么这个preProcess()就是你预留的钩子下游可以实现也可以不实现。所以看完这篇文章大家可以静下心来想想自己之前做过的项目中有哪些用到这两种模式然后自己再结合具体的场景总结一下我想你应该会对这两个模式有更深入的理解。