Java中的Strategy
模式和Polymorphism
之间有什么区别?
我很困惑,通过策略模式实现的任何事情基本上都可以通过多态实现。如果我在这方面错了,请纠正我。
请给我一个根除我的困惑的例子。
答案 0 :(得分:32)
对我来说,来自 CKing 帖子的链接和维基百科中的示例已经足够清楚了,但我会尝试给你一个新的例子。正如他们所说,策略模式主要是一种在运行时改变算法行为的方法。当然,你可以通过许多不同的方式实现这一点(例如持有一个值并使用switch-case,但它不如Strategy Pattern那么好。)
假设您正在开发一种回合制战略游戏,其中包含两种单位:步兵和坦克(单位的子类) 。您的地形可能是平原,铁路或森林。
class Unit{
MovementStrategy ms;
final int baseMovement;
int x,y;
public Unit(int baseMovement){
this.baseMovement = baseMovement;
}
abstract void fire();
void moveForward(){
x = x + ms.getHexagonsToMove(baseMovement);
}
void setMovementStrategy(MovementStrategy ms){
this.ms = ms;
}
}
任何单位子类都必须实现 fire()方法,因为它们将完全不同(坦克射击重型长距离射击和步兵射击几个短距离光子弹)。在这个例子中,我们使用普通的多态/继承,因为 fire()方法对于任何单位都会有所不同,在游戏中不会改变。
class Infantry extends Unit{
public Infantry(){
super(2);
}
void fire(){
//whatever
}
}
class Tank extends Unit{
public Tank(){
super(5);
}
void fire(){
//whatever
}
}
单位也可以移动,并且有一个 baseMovement 字段,用于保存它可以行走的六边形数量。我们正在开发一个策略游戏,而不是真实世界的模拟,所以我们不关心它们如何移动,我们只想在它们的坐标上添加一个值(在我的例子中,我只使用X坐标以获得更简单的代码)。如果所有地形都相同,我们就不需要任何策略对象......但我们需要在运行时更改move()方法的行为!
因此,我们为每种Terrain实现了一个不同的 MovementStrategy 类,我们将游戏编程为触发 setMovementStrategy()到任何继续前进的单位每个六边形。我们甚至不需要在Unit子类中编写任何其他内容。
interface MovementStrategy{
public int getHexagonsToMove(int base);
}
class PlainMovementStrategy implements MovementStrategy{
public int getHexagonsToMove(int base){
return base;
}
}
class RailroadMovementStrategy implements MovementStrategy{
public int getHexagonsToMove(int base){
return base*3;
}
}
class ForestMovementStrategy implements MovementStrategy{
public int getHexagonsToMove(int base){
return (int)(base/2);
}
}
现在,当任何单位在森林内移动时,我们会调用
unit.setMovementStrategy(new ForestMovementStrategy());
一旦进入 Plain ,我们就会:
unit.setMovementStrategy(new PlainMovementStrategy());
现在我们可以根据地形改变单位移动的距离,我们不需要在任何子类中重写。
我希望这可以帮助您更好地理解差异。
答案 1 :(得分:20)
我很困惑,通过策略模式实现的任何事情基本上都可以通过多态实现。
没有方向盘你不能驾驶汽车。这并不意味着方向盘就是汽车。同样,策略模式依赖于多态,但这并不意味着它们是相同的。
策略模式的目的是促进使用组合(has-a)而不是继承(is-a)。您可以在单独的类中定义行为,而不是您的类从超类继承行为,而您的类具有对它的引用。
就一个例子而言,看一看做得很好的this答案。
答案 2 :(得分:9)
多态性与具有核心java示例的策略模式
基本差异:多态性是编程语言概念,策略模式是behavioral design pattern of GoF之一。
多态性是为不同类型的实体提供单一界面。
示例:无论使用何种类型的实际转向机构,方向盘(即接口)都是相同的。也就是说,无论您的汽车是手动转向,动力转向还是齿条齿轮转向,方向盘都能正常工作。因此,一旦您知道如何操作方向盘,您就可以驾驶任何类型的汽车。
在编程中,多态性以两种方式实现:
编译时间:您(开发人员)正在编译代码的时间段 运行时间:用户运行软件的时间段 Source
Strategy pattern 定义了一组可互换使用的算法。
核心java的示例:java.util.Comparator#compare()
,由Collections#sort()
执行。
交通方式类似于策略设计模式。我们使用汽车,自行车,公共汽车,当地火车等..日常办公的不同策略。
答案 3 :(得分:7)
问:策略模式和多态性之间有什么区别 在Java?
问题肯定令人困惑,因为最初这两个想法之间似乎没有任何关系。
多态性在编程中是一个更广泛的概念,是的,Java中的策略模式使用一种多态性形式编目为inclusion polymorphism来实现其意图,但这绝不是唯一存在的多态性类型,也不是这是实施战略模式的唯一方法,我将尽快展示。
同样,多态性不仅仅存在于Java或面向对象的编程语言中。所有编程范例中都存在不同形式的多态,而不是在所有语言中,您都被迫使用多态来实现策略模式(例如函数式语言)。
有关此主题的进一步讨论,请阅读this other answer,我们已经讨论了在没有继承的情况下是否可以实现多态性,并且我为其他类型的多态性提供了有趣的参考和示例,如参数和ad-hoc多态。
理想情况下,这将向您揭示多态性是一个更大的概念,它超越了面向对象编程的界限,甚至超越了继承和子类型。
问:我很困惑,无论通过策略模式实现的是什么 基本上可能是多态性。如果我错了,请纠正我 方面。
从我的观点来看,这两个概念之间的关系是:策略模式利用Java等语言中可用的多态性来实现其意图,并且多态性本身可以被视为一种模式。
例如,请考虑GoF书中的这句话:
如果我们假设过程语言,我们可能会包含设计 模式称为“继承”,“封装”和“多态”。
只是我们很少将多态性视为一种模式,首先是因为它意味着许多事情,并且因为它在不同语言中的实现方式不同,而且因为它通常表现为某种形式的语言特征。
在他的“元素设计模式”一书中,杰森麦克史密斯评论上面的GoF引用说:
模式是与语言无关的概念;他们采取形式并成为 在特定的实现中具体解决方案 具有一组语言特征和结构的语言[...] 这意味着谈论“Java设计”有点奇怪 模式“,”C ++设计模式“,”Websphere设计模式“等等, 即使我们都这样做了。这是一种温和懒惰的速记形式 我们真正的意思,或者应该意味着:设计模式实现于 Java,C ++,WebSphere等,无论语言或API。
因此,正如您所看到的,您正在从Java实现的角度思考策略模式,但在其他语言范例中,这种模式可能以不同的方式实现,可能根本不使用继承,例如,在纯函数式编程语言中,这肯定是使用high order functions和function composition实现的。
因此,这将是一种策略模式实现,而根本不依赖于包含多态性。在函数组合策略中,我们可能仍在使用其他形式的多态(例如参数),但这不是策略模式的要求
问:请给我一个根除我的困惑的例子。
如上所述,在Java中,我们可能被迫使用包含多态来实现策略模式,但如上所述,模式不属于特定语言,因此如果我们将策略模式视为生活在任何语言边界之外的概念,您将很容易看到其他语言以不同的方式实现这一点。
在一些假设的函数式语言中,我可能有一个函数从文件中读取一些数据,也许文件是加密的,你需要提供解密策略:
function readFile(path: String, decrypt: string -> string) {
return decrypt(loadFromDisk(path));
}
并且decrypt
参数是一个服务于策略模式的函数,它封装了一个可互换的算法。
现在你可以做到
readFile("customers.txt", aes)
readFile("finance.txt", blowfish)
aes
和blowfish
是解密函数策略。
有许多语言可以像这样工作,SML,Haskell,JavaScript等。
答案 4 :(得分:5)
如果您要建立一个类比:
然后差异是耦合程度,在第一种情况下非常强,而在第二种情况下,任何外国代码都可以通过贡献其战略实施来参与你的阶级逻辑。
答案 5 :(得分:3)
首先。多态性可能意味着两种不同的东西。最常见的多态性是指多态类型。但是,你要求的是模式。
多态代码每次运行时都会自行更改,而代码的功能保持不变。一个简单的例子是1 + 3 = 4而不是5-1 = 4。两者都使用不同的代码实现相同的结果。这对于不希望被识别的代码很有用,即计算机病毒或加密代码。
另一方面,策略模式使用一系列可以互换的算法。在翻译文本时可能会使用此选项。首先,一些代码确定语言。如果语言是瑞典语或西班牙语,则该文本将由同一系列的不同功能,translateSwedish()或translateSpanish()处理。圆满结束。多态代码使用不同的代码来实现相同的结果。虽然策略使用不同的代码来获得更好的结果。
答案 6 :(得分:2)
考虑一下
我们有动物和策略模式对象来描述他们如何移动...... 例如
飞/游泳/步行
鉴于使用这些方法中的大量动物(即成千上万种不同的动物飞行),我们需要对许多不同的动物使用相同的代码。该代码应该只存在于一个地方,因此很容易更改,并且不会占用任何不需要的空间。
在此示例中,直接的多态方法将导致大量代码重复。一种更为复杂的方法是在动物和知更鸟之间放置一个中间阶层而不考虑动物如何移动并不是真正定义动物的方法。此外,动物可能有其他策略对象,并且不能通过中间类对它们进行多态化。
答案 7 :(得分:2)
多态性的一个定义是为不同类型的实体提供单个接口。
考虑到这一点,你说你有一个“鸟”界面,你所有的鸟类都必须实现“laysEggs()”方法,没有大问题可行。当你继续编写你的“鸟类天堂程序”时,你现在添加“fly()”并意识到企鹅和猕猴桃的超载和覆盖是不必要的,因为在现实生活中它们无法飞行,但你仍然必须实现这种方法。当你面对鸵鸟和其他无法飞行的人时,这会变得单调乏味而且毫无意义。甚至在添加“游泳()”方法时最糟糕的是因为更少的鸟类可以游泳。您可能已经知道,策略模式解决了这个问题。
在lame-man的术语中,您可以将多态性视为实践的集合体,而策略模式是特定案例的最佳实践。示例:当需要在运行时选择算法的行为时(通过可互换的算法),将使用策略模式。尽管通过多样性基本上可以实现通过策略模式实现的任何事情都是正确的,但是如果不了解策略模式,这将使您“重新发明轮子”问题来解决这个特定问题。总之,即使一个基于另一个,它们也是非常不同的。 我会让你看到“Ender Muab'Dib”代码,因为如果你仍然想要我的代码示例,只要问,欢呼和希望我帮助你就会得到很好的解释。
答案 8 :(得分:2)
多态性是一种原则,策略是一种设计模式
来自oracle文档page
多态性的字典定义是指生物学中的原理,其中生物体或物种可以具有许多不同的形式或阶段。这个原则也可以应用于面向对象的编程和Java语言之类的语言。类的子类可以定义它们自己的唯一行为,但是可以共享父类的一些相同功能。
可以在编译时(方法重载)和运行时(方法重写)实现多态性。
策略可以使用运行时多态性原则来实现所需的功能。
策略模式在其URL图中还有一个名为Context的组件。 请参阅以下SE帖子:
Real World Example of the Strategy Pattern
Does this Java Strategy pattern have a redundant Context class?
更多有用的文章:
源代码制作答案 9 :(得分:0)
简明扼要的答复是:
因此,如果要使用Java(即OOP)实现策略模式,则只需使用多态。
换句话说,策略模式是多态的多种形式之一。