使用策略设计模式 - Keep It Simple Series创建部分常见操作(方法)的可重用组件
介绍
在我们开始之前。让我回答下面的问题。
问题是什么?
为什么我们需要策略设计模式才能解决问题?
让我以一个例子来解释这个问题。有一个超类--S它有四个子类--A,B,C和D.有一个操作(你可以说是一个方法)O,它有两个版本的实现。操作O的一个版本对于子类-A和C是通用的。操作O的另一个版本对于子类-B和D是通用的。我们不能简单地将此操作O放在超类S中,因为操作O具有两个版本的实现和这两个版本并不是所有子类共有的。每个版本的操作O都是部分通用的。
一解决方案
我们可以为每个子类实现特定的操作O版本。但在这里我们重复自己。好的设计没有重复。重复使系统难以维护,难以扩展并易受漏洞攻击。因此,这个解决方案不是一个完美的解决方案
更清洁的解决方案
使用策略设计模式!
如果您仍然没有遇到问题,请不要担心。我们将在整篇文章中讨论这个问题。
现在让我们了解我们的超级英雄战略设计模式将如何拯救我们的一天。
背景
有一个简单的Bird百科全书系统。它模拟鸟类的行为,如飞行,游泳等。在引擎盖下,有一个鸟引擎,这使所有这些事情成为可能。我们来讨论一下鸟引擎的初步设计。有一个叫做的超类 Bird。它是一个 abstract 类,具有所有常见的操作(方法)实现。有鸟的三个具体的类- Swan, Albatross 并且 Gull,它继承的 Bird 类。让我们看一下图表,这样我们就能更好地理解事物。请注意这里的一件事,我们从来没有去过代码级别的细节,因为它是一篇设计文章。把事情简单化。
如上图所示:
Bird class有以下操作(方法):
- fly():实现飞行逻辑
- swim():游泳逻辑的实施
- walk():实现步行逻辑
- makeSomeNoise():它是一个抽象(一个没有实现的操作,只是一个骨架)操作。每只鸟都有独特的声音。因此,每个子类都必须提供自己的实现
- display():这是一个抽象的操作。每只鸟都有独特的外观。因此,每个子类都必须提供自己的实现。
Swan class有以下操作:
- makeSomeNoise():实施天鹅之声
- display():实施天鹅外观
Albatross和Gull类相同的东西。
所有常见的鸟类操作都在Bird超类中定义。因此,我们不需要在具体的鸟类中重复自己。好的设计总是鼓励可重用性。
问题是什么
变化是软件行业唯一不变的因素。现在在鸟引擎中,我们需要添加另一个bird名为 - 的类Penguin。Penguinclass必须Bird按照我们的设计继承类。因此, Penguinclass继承了Bird类的所有操作。但问题是Bird阶级有fly()运作,我们可怜的企鹅不能飞。除非企鹅是来自马达加斯加的船长。我们现在该做什么?
我们可以拉出fly()从操作Bird类,并实现它的所有具体子类- Swan,Albatross和Gull。但是如果我们这样做,那么我们就会牺牲可重用性,并且我们会在包括Penguin类在内的所有具体子类中重复自己。由于Penguin类应该实现fly()无飞行实现的操作。
那么,为了以更清洁的方式解决问题,我们应该怎么做?
解决方案阳光
为了更清洁地解决这个问题,我们fly() 从Bird类中拉出了操作的实现 。然后我们创建一个FlyBehaviour抽象类并fly()在其中定义抽象操作。
FlyBehaviour abstract类有以下抽象操作:
- fly():这是一个抽象操作,因为我们有两个版本的fly()操作。
然后我们定义两个具体的子类 - CanFly并CannotFly继承FlyBehaviour抽象 类。
CanFly class有以下操作:
- fly():实施一只鸟飞
CannotFly class有以下操作:
- fly():对那些无法飞行的鸟类一无所知。
让我们看看更新的图表,而不是让事情变得更复杂。
这FlyBehaviour是一个接口,因为它没有实现。
Bird 抽象类结构仅更新:
- flyBehaviour:它是一种类型的属性FlyBehaviour。它可以容纳CanFly或CannotFly具体类型。它可以通过setFlyBehaviour()操作设置 。
- setFlyBehaviour():它FlyBehaviour为flyBehaviour属性设置具体的子类类型。如果具体 Bird类型是Penguin,flyBehaviour则应设置为CannotFlytype。对于其他具体 Bird类型,flyBehaviour应设置为CanFlytype。
- fly():现在,此操作只调用 属性fly()上的操作flyBehaviour。底层具体类型(CanFly或CannotFly)FlyBehaviour处理操作行为。
这称为组合。组成Bird类型和FlyBheaviour类型。确定应用程序的各个方面的变化,并将它们与保持不变的方面分开。这样,我们就可以创建部分常见操作的可恢复组件。
另一个问题是:
现在我们需要在我们的鸟类引擎中添加一只叫做 - 的鸟Frigatebird。所以,我们的Frigatebird类必须Bird按照设计继承类。因此, Frigatebird 类继承了类的所有操作Bird。但问题是我们的穷人Frigatebird不会游泳。我们现在该做什么?
你最好知道我们现在该做什么。尝试自己解决这个问题。你可以在下面找到它的解决方案,但不要做作弊。
解决方案阳光再次
我不打算再重复一次。所以我让图表说出你所知道的:
引用:一张图片胜过千言万语。
结论
我们用于创建部分常见操作的可重用组件的设计解决方案称为 - 策略设计模式。现在我们的鸟类发动机设计非常灵活,我们可以在不改变其他类别的情况下添加更多混凝土鸟类。我们需要做的只是添加类,就是这样。每个引擎的设计都应该鼓励可重用性,可扩展性和可维护性。在一天结束时,一个好的设计将为您节省大量的精力和金钱。每种设计模式的目标是创建可重用,可扩展和可维护的系统。
现在是战略设计模式官方定义的时代:定义一系列算法,封装每个算法,并使它们可互换。策略允许算法独立于使用它的客户端。