Collections.sort使用什么设计模式?

15

当按照以下方式将比较器应用到列表时,使用的是什么设计模式或这里使用的是什么技术?

Collections.sort(myCollection, new Comparator<MyItem>() {

    @Override
    public int compare(MyItem item1, MyItem item2) {
        return item1.getId().compareTo(item2.getId());
    }

});

19
策略模式是一种常用的设计模式,用于定义一系列算法,并将每个算法封装起来,以便它们可以相互替换。通过这种方式,程序可以在运行时动态地选择要使用的算法,从而实现更灵活的行为。在策略模式中,通常会有一个上下文对象来管理不同的策略,并在需要时调用适当的策略。 - Andy Turner
@CKing,你能想到一个行为设计模式,它不是“你通常的多态性在行动中”吗? - Andy Turner
"策略模式有一个明确定义的结构",那是什么? - Andy Turner
@AndyTurner 结构 - Chetan Kinger
1
@AndyTurner GoF 的 Eric Gamma 在谈论策略模式时说:“对象组合提供了一种更可行和灵活的扩展机制。” 对象组合是“策略模式”的定义关键。我希望我可以同意不同意见,但我不能,因为在多态性和策略模式方面存在微妙但明显的差异。设计模式使用语言提供的基本构建块,但它与这些构建块不可互换。 - Chetan Kinger
显示剩余5条评论
3个回答

14

TL;DR

Collections.sort 是一个简单的多态替换示例,无论您是使用函数式编程还是面向对象编程进行此替换。术语策略模式不能与多态函数式编程互换使用。

可以说我们仍在将排序策略传递给sort方法,但是没有Context,它不等同于策略模式


当以以下方式将比较器应用于列表时,使用的是哪种设计模式或技术?
由于此问题已被标记为OOP,因此没有使用OOP设计模式。这是纯粹的多态性在发挥作用。一些程序员可能称之为策略模式,但我不同意。策略模式提倡组合而不是继承,其中使用“has-a”关系而不是“is-a”关系。
一些程序员可能会进一步争论说我们正在将一个排序策略传递给Collections.sort方法,因此这是策略模式;然而,需要承认的是,Strategy是策略模式的组成部分之一。策略模式的另一个重要组成部分是它的Context,它与Strategy建立了HAS-A关系。这个组件是策略模式背后动机的核心,即优先使用组合而非继承。你不能把整体的一部分拿出来,仍然称那个分离的部分为整体。你不能把Context从策略模式中取出来,仍然称其余部分为策略模式。
Collections.sort是一个静态方法,允许您在运行时多态地替换要使用的Comparator实现。

支持材料

让我们从GoF中了解一下策略模式的定义:

将算法封装在对象中是策略(315)模式的意图。模式中的关键参与者是策略对象(它们封装不同的算法)以及它们所操作的上下文。组合器是策略;它们封装不同的格式化算法。组合是组合器策略的上下文

....

对象组合提供了一个可能更可行和灵活的扩展机制。

现在应该清楚了,多态策略模式之间有微妙的区别。 策略模式讨论了一个上下文,如上面加粗所示,使用组合Collections类不与比较器建立组合关系。此外,策略模式class diagram显示了一个称为上下文的组件,它组成了策略接口。

这个问题被标记为OOP,但如果我们想谈论当涉及到函数式编程范例时Collections.sort代表什么模式,我会说它代表函数式编程。(如果我必须将将函数传递给方法等同于OOP模式,我会说它与命令模式更相似(而非完全类似)于策略模式

相关内容: 函数式编程是否可以替代GoF设计模式?


评论不适合进行长时间的讨论;此对话已被移至聊天室 - Bhargav Rao
1
最简洁的陈述在第316页上,“_策略提供了一种配置类的方法..._”如果策略提供了一种配置方法的方式,那么这本书会这样说的。(当我解释GoF时,我倾向于文本主义的观点。) - jaco0646

7
Collections.sort()使用策略模式。

1
我不同意。策略模式有一个明确定义的结构,而Collection.sort没有使用。策略模式倡导组合而非继承。策略模式多态性不是可互换的术语。 - Chetan Kinger
@ChetanKinger - 在识别使用/将要使用的模式时,哪个更重要:实现还是意图?策略意图是:将算法的一部分(比较逻辑)传递给另一个(排序),从而证明方法的DRY实现,其中主算法可以被重用。在Java中,只能通过对象来实现,因为它从未支持高阶函数。函数式策略模式使这变得简单-您只需传递一个函数即可。面向对象编程中的策略-必须将逻辑封装到对象中。简单而优雅的解释,尽管您的字面主义不容忽视。 - Mindaugas Bernatavičius

2
我认为首先可以看一下另一种形式的Collections.sort(myCollection),它不需要在运行时对项进行比较的算法。在这种方法中,它使用继承为项提供的算法(通过实现Comparable接口)。虽然这种方法不是直接的方式,但如果我们稍微灵活一点看待它,这就是一个模板模式。这种方法使用了继承,而且项的行为在运行时不能改变。
但在第二种形式的Collections.sort(myCollection, comparing-algorithm)中,我们将行为传递给了运行时,与继承的模板模式不同,在运行时使用可提供和可更改的行为,这是策略模式最重要的部分。
有人可能会问在这里的策略模式的组合部分在哪里?组成部分只是保存算法,以便在需要时使用它。但在这种情况下,每当需要算法时,它都被作为参数传递,因为Collections类是一个Utils类,用于不同的目的,并非我们在原始版本的策略模式中看到的上下文类。

动态调度和运行时多态是每种面向对象语言的成熟功能/结构。面向对象设计模式建立在这些语言功能/结构之上。认为动态调度类似于模板模式或方法参数中的多态替换,与策略模式相同,这是不可取且不符合直觉的。设计模式的优势在于它们的沟通效果。如果我们开始将每个语言功能/结构等同于一个设计模式,我们会产生混乱,并使这些模式无用。 - Chetan Kinger

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接