多态与策略模式

Polymorphism vs Strategy pattern

Strategy 模式和 Java 中的 Polymorphism 有什么区别?

我很困惑,无论通过策略模式实现什么,多态性基本上都是可能的。如果我在这方面有误,请纠正我。

还请提供示例以消除我的困惑。

如果您要建立一个类比,其中:

  • 在一种情况下,您有多个可覆盖的方法;
  • 在另一种情况下,您有一个包含多个实现的 Strategy 接口,

那么区别在于耦合程度,在第一种情况下耦合度非常高,而在第二种情况下,任何外部代码都可以通过贡献其 Strategy 实现来参与您的 class 逻辑。

I'm confused that whatever is achieved via Strategy Pattern is basically possible by polymorphism.

没有方向盘就不能开车。这并不意味着方向盘就是汽车。同样,策略模式依赖于多态性,但这并不意味着它们是同一回事。

策略模式的目的是促进使用组合 (has-a) 而不是继承 (is-a)。您的 class 不是从超级 class 继承行为,而是在单独的 class 中定义该行为,并且您的 class 具有对它的引用。

就示例而言,请查看 this 做得很好的答案。

考虑这个

我们有动物和一个策略模式对象来描述它们如何移动... 例如

fly/swim/walk

鉴于使用这些方法中的任何一种的动物数量众多(即成千上万种不同的动物会飞),我们需要对许多不同的动物使用相同的代码。该代码应该只存在于一处,以便于更改并且不会占用任何不需要的 space。

在此示例中,直接的多态性方法将导致大量代码重复。一种更复杂的方法在动物和说知更鸟之间放置一个中间 class 未能考虑到动物的移动方式并不是真正定义它的因素。此外,动物可能有其他策略对象,并且它们不能通过中间 classes.

全部变为多态。

对我来说,CKing post 中的 link 和维基百科中的示例已经足够清楚了,但我会尝试给你一个新的例子。正如他们所说,策略模式主要是一种在运行时改变算法行为的方法。当然你可以通过许多不同的方式来实现这一点(比如持有一个值和使用 switch-case,但它不会像策略模式那样好)。

假设您正在开发一款回合制策略游戏,有两种单位步兵 Tank(单位的 subclasses)。您的地形可以是 平原铁路森林.

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;
    }
}

任何 subclass 单位都必须实施 fire() 方法,因为 它们将完全不同(坦克射击重型长距离子弹和步兵射击几颗短距离轻型子弹)。在这个例子中我们使用普通的 polymorphism/inheritance 因为 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 坐标以获得更简单的代码).如果所有地形都相同,我们就不需要任何 Strategy 对象...但是 我们需要在运行时更改 move() 方法的行为!

因此,我们为每种类型的地形实施不同的 MovementStrategy class,并且我们对游戏进行编程以触发 setMovementStrategy( ) 到每个六边形上移动的任何单位。我们甚至不需要在 Unit subclasses.

中写任何其他内容
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 移动到 Forest 内时,我们调用

unit.setMovementStrategy(new ForestMovementStrategy());

一旦它变成 Plain,我们就会:

unit.setMovementStrategy(new PlainMovementStrategy());

现在我们可以根据地形改变我们的单位移动的距离,我们不需要在任何子classes中重写。

希望这能帮助您更好地理解其中的区别。

首先。多态性可能意味着两种不同的事物。最常见的多态性是指多态类型。但是,您要求的是模式。

多态代码可以在每次运行时改变自身,而代码的功能保持不变。一个简单的例子是做 1+3=4 而不是 5-1=4。两者都使用不同的代码实现了相同的结果。这对于不想被识别的代码很有用,即计算机病毒或密码代码。

另一方面,策略模式使用一系列可以互换的算法。这可能在翻译文本时使用。首先,一些代码决定了语言。如果语言是瑞典语或西班牙语,文本将由同一系列的不同函数 translateSwedish() 或 translateSpanish() 处理。

四舍五入。多态代码使用不同的代码来实现相同的结果。而 Strategy 使用不同的代码来获得更好的结果。

  • 基本区别:多态性是编程语言概念,策略模式behavioral design pattern of GoF之一.

  • 多态性是为几种不同的底层数据类型提供单一接口。

    • 示例:无论实际使用哪种类型的转向机构,方向盘(即接口)都是相同的。也就是说,无论您的汽车是手动转向、动力转向还是齿轮齿条式转向,方向盘的工作原理都是一样的。因此,一旦你知道如何操作方向盘,你就可以驾驶任何类型的汽车。

    • 在编程中,多态性有两种实现方式:

      • Early-Binding/Static/Compile-Time 多态性(例如:函数重载)
      • Late-Binding/Dynamic/Run-Time 多态性(例如:函数覆盖)
  • A Strategy pattern 定义了一组可以互换使用的算法。

    • 策略模式是一种动态模式(您希望运行软件中的行为如何?)。

    • 核心示例 java:java.util.Comparator#compare(),由其他 Collections#sort().

      执行
    • 交通方式类似于战略设计模式。我们使用汽车、自行车、公共汽车、当地火车等..每天上班的不同策略。

Q: What is the difference between the Strategy pattern and Polymorphism in Java?

这些问题肯定令人困惑,因为最初这两个想法之间似乎没有任何关系。

多态性在编程中是一个更广泛的概念,是的,Java 中的策略模式使用一种编目为 inclusion polymorphism 的多态性形式来实现其目的,但这绝不是唯一的类型存在的多态性,它也不是实现策略模式的唯一方法,正如我即将展示的那样。

此外,多态性并非仅存在于 Java 或面向对象的编程语言中。不同形式的多态存在于所有编程范例中,而不是在所有语言中都存在,您被迫使用多态来实现策略模式(例如函数式语言)。

有关此主题的进一步讨论,请阅读 this other answer,我们在其中讨论了多态性是否可以在没有继承的情况下实现,并且我提供了其他类型的多态性(如参数多态性和临时多态性)的有趣参考和示例。

理想情况下,这将向您揭示多态性是一个更大的概念,它超越了面向对象编程的界限,甚至超越了继承和子类型。

Q: I'm confused that whatever is achieved via Strategy Pattern is basically possible by polymorphism. Correct me if I'm wrong in this regard.

从我的角度来看,这两个概念之间的关系是:策略模式利用 Java 等语言中可用的多态性的力量来实现其意图,并且多态性本身可以被视为图案。

例如,考虑一下 GoF 书中的这句话:

If we assumed procedural languages, we might have included design patterns called 'inheritance', 'encapsulation' and 'polymorphism'.

只是我们很少将多态性视为一种模式,首先是因为它意味着很多事情,因为它在不同语言中的实现方式不同,还因为它通常表现为某种形式的语言特征。

Jason Mc C. Smith 在他的《元素设计模式》一书中评论了上面引用的 GoF 的话:

Pattern are language-independent concepts; they take form and become concrete solutions when you implement them within a particular language with a given set of language features and constructs [...] This means that it is a bit strange to talk about "Java design pattern", "C++ design patterns", "Websphere design pattern" and so on, even though we all do it. It's a mildly lazy form of shorthand for what we really mean, or should mean: design patterns as implemented in Java, C++, WebSphere and so on, regardless of language or API.

因此,如您所见,您是从 Java 实现的角度思考策略模式,但在其他语言范例中,这种模式可能以不同的方式实现,可能没有使用继承完全,例如,在纯函数式编程语言中,这肯定是使用 high order functions and function composition.

实现的

因此,这将是一种策略模式实现,根本不需要 包含多态性。在函数组合策略中,我们可能仍在使用其他形式的多态性(例如参数),但这不是策略模式的要求

Q: Please, also provide me example to eradicate my confusion.

如上所述,在 Java 中,我们可能被迫使用包含多态性来实现策略模式,但同样如上所述,模式不属于特定语言,因此如果我们将策略模式视为一个存在于任何语言边界之外的概念,那么您将很容易看到其他语言以不同的方式实现它。

在一些假设的函数式语言中,我可能有一个从文件中读取一些数据的函数,也许文件是加密的,你需要提供一个解密策略:

function readFile(path: String, decrypt: string -> string) {
    return decrypt(loadFromDisk(path));
}

而那个 decrypt 参数是一个服务于策略模式的函数,它封装了一个可互换的算法。

现在你可以做

readFile("customers.txt", aes)
readFile("finance.txt", blowfish)

其中aesblowfish为解密函数策略

像这样工作的语言有几十种,SML、Haskell、JavaScript 等

多态的一个定义是为不同类型的实体提供单一接口。

考虑到这一点,假设您有一个“鸟”界面,并且您所有的鸟 类 都必须实现“laysEggs()”方法,这没什么大不了的。当你继续编写你的“鸟类天堂程序”时,你现在添加了“fly()”并意识到企鹅和猕猴桃的重载和覆盖是不必要的,因为在现实生活中它们不能飞,但你仍然必须实现该方法。当您面对鸵鸟和其他不会飞的动物时,这可能会变得乏味且毫无意义。甚至在添加方法“swim()”时情况更糟,因为会游泳的鸟更少了。你可能已经知道,策略模式解决了这个问题。

用蹩脚的术语来说,您可以将多态性视为实践的集合体,而策略模式是特定案例的最佳实践。示例:当需要在运行时(通过可互换算法)选择算法的行为时,将使用策略模式。虽然通过策略模式基本上可以通过多态性实现任何目标,但如果不了解策略模式,这会让您面临“重新发明轮子”的问题来解决这个特定问题。总之,即使一个基于另一个,它们也非常不同。 我会留给你看“Ender Muab'Dib”代码,因为如果你还想从我这里得到一个代码示例,它已经得到了很好的解释,请问,干杯,希望我能帮到你。

多态是原则,策略是设计模式

来自 oracle 文档 page

The dictionary definition of polymorphism refers to a principle in biology in which an organism or species can have many different forms or stages. This principle can also be applied to object-oriented programming and languages like the Java language. Subclasses of a class can define their own unique behaviors and yet share some of the same functionality of the parent class.

多态性可以在编译时(方法重载)和运行时(方法覆盖)实现。

Strategy_pattern

  1. 定义了一系列算法,
  2. 封装每个算法,
  3. 使该系列中的算法可以互换。

策略可以利用运行时间多态性原理来实现想要的功能。

策略模式在其 URL 图表中还有一个名为 Context 的组件。 参考以下 SE 帖子:

Real World Example of the Strategy Pattern

Does this Java Strategy pattern have a redundant Context class?

几篇更有用的文章:

strategy 来自 sourcemaking

这里是简明的回复:

  1. 多态性是基本特征之一 面向对象编程。
  2. 策略模式是一种独立于语言的模式,所有人都可以实现 编程语言范式,例如命令式、函数式和 面向对象。

因此,如果你要使用Java实现策略模式,也就是OOP,那么你只需要使用多态性。

换句话说,策略模式是多态的多种形式之一。