策略模式
和Java中的多态
有什么区别?
我很困惑,无论是通过策略模式
还是多态
都可以实现相同的效果。如果我在这方面错了,请纠正我。
请举例说明以消除我的疑惑。
策略模式
和Java中的多态
有什么区别?
我很困惑,无论是通过策略模式
还是多态
都可以实现相同的效果。如果我在这方面错了,请纠正我。
请举例说明以消除我的疑惑。
对我来说,来自CKing的帖子链接和Wikipedia上的示例已经足够清晰了,但我会尝试给您举一个新的例子。正如他们所说,策略模式主要是一种在运行时更改算法行为的方法。当然,你可以用许多不同的方式实现这一点(比如保存一个值并使用switch-case,但这并不像策略模式那样好)。
假设你正在开发一个回合制战略游戏,有两种类型的单位: 步兵 和坦克(它们都是 Unit 的子类)。你的地形可能是平原、铁路或森林。
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;
}
}
任何Unit子类都必须实现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()方法的行为!
因此,我们为每种地形实现一个不同的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());
现在我们能够根据地形的不同来改变我们的单位移动的距离,而且我们不需要在任何子类中重新编写。
希望这可以帮助您更好地理解差异。
基本差异:多态是编程语言的概念,策略模式则是GoF中的一种行为型设计模式之一。
多态提供了一个单一的接口,可以用于多个不同的底层数据类型。
例如:方向盘(即接口)无论实际使用的转向机制是手动转向、动力转向还是齿轮齿条转向都是一样的。因此,一旦您知道如何操作方向盘,就可以驾驶任何类型的汽车。
在编程中,多态有两种实现方式:
策略模式定义了一组可相互替换使用的算法。
策略模式是一种动态模式(如何在软件中运行行为?)。
Java核心中的示例:java.util.Comparator#compare()
,由Collections#sort()
等执行。
交通工具的不同出行策略类比于策略设计模式。我们每天使用汽车、自行车、公交车、地铁等不同的策略去上班。
因此,正如您所看到的,您从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等的编程语言都可以这样工作。
多态是一种原则,策略模式是一种设计模式
来自Oracle文档页面
多态的词典定义指的是生物学中一个生物或物种可以有许多不同的形态或阶段。这个原则也可以应用于面向对象的编程和像Java语言这样的语言中。类的子类可以定义自己独特的行为,但仍然共享父类的某些功能。
多态可以在编译时(方法重载)和运行时(方法重写)实现。
策略可以使用运行时多态原则来实现所需的功能。
策略模式还有一个称为上下文的组件。参考下面的SE帖子:
更多有用的文章:
sourcemaking的策略
多态的一种定义是为不同类型的实体提供单一接口。
以此为背景,假设你有一个“鸟”接口,所有的鸟类都必须实现“laysEggs()”方法,那么这没问题。随着你继续编写“鸟乐园程序”,你现在添加了“fly()”,并意识到对企鹅和几维鸟进行重载和覆盖是不必要的,因为它们不能飞,但仍然必须实现该方法。当你面对鸵鸟等无法飞行的鸟类时,这可能变得烦琐和无意义。更糟糕的是,当添加“swim()”方法时,因为能游泳的鸟类更少。正如你可能已经知道的那样,策略模式解决了这个问题。
简单地说,你可以将多态看作一系列实践,而策略模式则是特定情况下的最佳实践。例如:当需要在运行时选择算法行为(通过可互换的算法)时,应使用策略模式。虽然基本上可以通过多态实现策略模式所实现的任何功能,但如果没有策略模式的知识,这会让你陷入“重复制造轮子”的问题来解决这个特定的问题。总之,即使一个基于另一个,它们也是非常不同的。
如果你还需要一个代码示例,可以查看“Ender Muab'Dib”的代码,因为这是很好解释的。希望我能有所帮助,祝好!
以下是简明回答:
因此,如果您要使用Java(即OOP)实现策略模式,则只需使用多态性。
换句话说,策略模式是多态性的许多形式之一。