C++ 设计模式库?

13

什么是最常见的C++设计模式库?

我读过Alexandrescu的书中关于Loki库的介绍,但看起来现在它有些失效了。是否有类似的库可用?


6
请参阅此演示文稿,了解一种现代的C++11方法来使用GoF设计模式。 - TemplateRex
1
我已经重新措辞了问题,也许我们可以重新开放它? - cody
1
嗯?Loki库已经废弃了? - Adri C.S.
@AdriC.S. 至少最新版本是在2009年1月发布的。 - cody
并不是说“loki已经死了”。事实上,Loki实现的许多东西现在(采用不同的方法)成为C++11的一部分。其中只剩下很少的东西。 - Emilio Garavaglia
@TemplateRex:你的评论应该成为一个答案! - Emilio Garavaglia
4个回答

25
"设计模式是针对程序语言的漏洞报告" -- Peter Norvig
要回答为什么没有很多C++设计模式库这个问题,了解设计模式最初的解决方法非常有用。经典的GoF书籍在前言中陈述:
"设计模式描述面向对象软件设计中特定问题的简单而优雅的解决方案。"
面向对象编程的90年代风格严重依赖于使用抽象类作为接口,并从这些接口派生具体实现类。GoF模式描述了不同类类型的对象之间的创造性、结构和行为关系。它们的关键要素是:“封装和参数化任何经常更改的内容”。许多GoF模式也可以使用模板重新表达,但是灵活性被限制为编译时而不是运行时。
面向对象编程使添加接口的不同具体实现非常容易。面向对象编程难以做到的是向现有接口添加新功能。 Visitor模式 就是一个主要的例子:它本质上是一个变通方法,依赖于额外的间接层,允许新算法在现有数据结构上工作。"

这与函数式编程截然相反:使用函数式编程很容易为现有数据添加新函数,但要为这些函数应用于的新数据类型添加新数据类型则更加困难。在函数和类型的可扩展性方面遇到的困难被称为表达式问题

OOP风格的多态性主要基于内部多态性:动态函数分派基于对象的类型。现代C++还使用外部多态性,其中诸如类型擦除之类的技术允许静态接口具有运行时灵活性。新的std::shared_ptrboost::anyadobe::poly类是这些技术的典型示例。

一份由Tobias Darm在ACCU演示中展示的内容,展示了许多将旧的内部多态GoF模式转换为新的外部多态模式的例子。大致思路是用一个函数参数替换抽象类,该函数参数可以接受std::function作为参数。然后std::function从外部控制多态灵活性。这种方法可以极大地提高许多GoF模式的样板代码。 TL;DR: 经典的GoF模式是为解决OOP的缺陷而设计的。但是,OOP不再是主流的C++风格。通用编程(标准库、Boost)和OOP的结合可以更优雅地解决许多问题,使经典的设计模式不再是首选解决方案。

Tobias Darm提供的想法非常有前途。是否有看视频的变化? - cody
@cody 我找不到那个视频。不确定是否所有ACCU会议都有录像。 - TemplateRex
我找到了这个视频:http://www.infoq.com/presentations/gof-patterns-c-plus-plus-boost - cody

17

设计模式的最初定义是一种可重复使用的方法,用于解决无法方便地封装在库中的反复出现的问题。因此,当您可以将一个模式封装在库中时,它在我看来就不再是一个模式了。例如,在C ++中,迭代器已经成为了一个非常完整的框架,因此它们已经不再是模式。

我从未尝试过使用Loki,但阅读Alexandrescu的书后,我并没有被说服认为基于库的方法对许多模式有太多的帮助。


这个问题主要是出于方便考虑。我经常使用自己手动实现的观察者模式和单例模式。但与其重新发明轮子,我更愿意使用广泛应用的解决方案。 - cody
5
但你并没有“重新发明轮子”。设计模式就是轮子,如果你遵循它的设计和术语,那么你正在使用“广泛使用”的东西; 实际上,比起编写针对“模式库”可能不太规范的约定,你更多地在使用它(当然也有例外,比如现代 C++ 中的迭代器,在这种情况下,库约定比 GoF 模式更加广泛使用)。 - microtherion
标准的C++库现在已经有了一个全面的迭代器实现框架。您能详细说明一下吗?我知道有迭代器特性(以及相关的“迭代器”基类),但我不知道标准库中是否有一个全面的迭代器实现框架 - dyp
@DyP,我可能有点夸张了... 我确实在想std::iterator_traitsstd::iterator,但也包括消费者基础设施,即符合标准库约定的迭代器也可以插入到其类别定义的所有标准库算法中。 - microtherion

3

可能看起来有些啰嗦,但最常见的是...标准库本身!

严格来说,它不是一个“模式库”,而是一个包含了许多工具的文件夹,用于解决常见的模式实现。

请注意,您的问题没有可回答性,因为“模式”只是在各种问题中常用的概念定义。库并不提供模式,它们(可以)使用模式来提供特定问题解决方案的实现(就像任何人都可以)。

模式在抽象层次上比编码更高级别。


你认为 Singleton、Observer、Visitor 或者抽象工厂等设计模式无法通过头文件模板来实现吗?我知道至少有一个库可以做到这一点:Loki。 - cody
Loki不是一个模式实现,而是一个使用这些模式提供工具来完成其他任务的库。定义类是编程对象,定义模板是编程类,定义概念是编程模板,定义模式是编程概念。Loki使用相同的名称并不意味着它是一个“模式”:它位于不同的抽象层上。 - Emilio Garavaglia
我明白你的意思。你在谈论设计模式的严格定义。实际上,我不需要那个。我需要一个带有模板类Observable(例如)的头文件,我将继承该类,并能够使用一些方法,如AddObserver和NotifyObservers,因此我将使用观察者模式。现在我清楚了吗? - cody
@Cody:是的,完美。关键在于你实现“可观察对象”的方式取决于你想要“观察”的方式。如果你使用给定的实现,你被迫遵循一种“耦合机制”,这可能不是你为了达到目的所需要的。说真的:看一下[http://accu.org/content/conf2013/Tobias_Darm_Effective_GoF_Patterns.pdf]:你会发现许多模式都在标准库中。你只需要知道它就可以了。 - Emilio Garavaglia
你的链接里多了一个']',所以它已经失效了。但是我正在阅读那个演示文稿。能够观看视频也会很好,但是目前我找不到链接。 - cody
修复链接:https://accu.org/content/conf2013/Tobias_Darm_Effective_GoF_Patterns.pdf - Emilio Garavaglia

0
为了提高代码的可维护性、可重用性和可读性,一些研究人员(如GoF、Booch)开始研究最佳实践。他们注意到有些经验丰富的开发者采用了一些模式来解决具体的设计问题。
正如你所看到的,经验创造了设计模式。因此,使用设计模式就像专家编码一样。但这并非银弹。
确实,一些简单的设计模式,如装饰者模式,会得到特定语言的支持。但这是有限制的。领域特定框架还指导你使用它们的接口来完成作者决定的设计模式。
库只能帮助你了解在该库中使用的设计模式如何促进你的实现。它甚至不会给你更改设计的选择。

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