什么是反模式?

272
我正在学习设计模式和反模式。对于设计模式,我有清晰的理解,但是我不太懂什么是反模式。我在网上和维基百科上找到的定义让我感到困惑。
有人能简单地向我解释一下反模式吗?它的目的是什么?它们都做些什么?这是好事还是坏事?

4
好的,我会尽力以通俗易懂的方式翻译这个网页上的内容,并尽量不改变原意。以下是需要翻译的内容:https://sourcemaking.com/antipatterns - jaco0646
5
http://martinfowler.com/bliki/AntiPattern.html - jaco0646
C2 wiki是由Ward Cunningham创建的原始维基网站,其中有很多关于编程模式的材料,以及一个关于反模式的页面。(如果您不熟悉该网站的概念设计,请先访问起始页面。它与人们现在所认为的“维基”相去甚远,尽管它显然启发了像维基百科和Wikia这样的平台的架构。) - tripleee
15个回答

340

反模式(Anti-patterns)是软件开发中被认为是不良编程实践的某些模式。

设计模式相反,后者是常见问题的常见解决方法,已经被规范化并普遍被认为是良好的软件开发实践。反模式则是相反的,是不可取的。

例如,在面向对象编程中,设计思路是将软件拆分成小的对象。面向对象编程的一个反模式是全能对象,它执行许多本应该分成不同对象的功能。

例如:

class GodObject {
    function PerformInitialization() {}
    function ReadFromFile() {}
    function WriteToFile() {}
    function DisplayToScreen() {}
    function PerformCalculation() {}
    function ValidateInput() {}
    // and so on... //
}

上面的例子有一个对象做了所有事情。在面向对象编程中,最好为不同的对象定义明确的责任,以保持代码耦合度低,最终更易于维护:

class FileInputOutput {
    function ReadFromFile() {}
    function WriteToFile() {}
}

class UserInputOutput {
    function DisplayToScreen() {}
    function ValidateInput() {}
}

class Logic {
    function PerformInitialization() {}
    function PerformCalculation() {}
}

归根结底,有一些好的方法可以使用常用模式(设计模式)来开发软件,但也有一些开发和实现软件的方式可能会导致问题。 被认为是不良软件开发实践的模式被称为反模式。


20
除了GodObject之外,还有哪些Anti-Patterns的例子? - Tomasz Mularczyk
1
@Tomasz编程意面服务就是其中一个例子。它最好被概括为许多小对象之间的差劣封装。可以将其视为上帝对象的相反。https://en.wikipedia.org/wiki/Spaghetti_code - AWrightIV
2
单例模式是否可以被视为反模式,因为它使得在并行运行测试时更难进行模拟(由于所有测试都使用和改变同一个单例,导致不一致性)? - lostsoul29
2
@lostsoul29,这取决于您的程序最终目的是否是能够并行测试......(而在您提到的特定情况下:这是一个可重入问题,应该进行纠正或记录)。Singleton确实是一种应该用于其擅长的模式。 - Matthieu
很棒的例子,谢谢,这非常清晰明了。现在我必须去重写我的所有代码... - physincubus
显示剩余2条评论

84
每当我听到反模式时,我就会想起另一个术语,即设计异味。
“设计异味是指设计中的某些结构表明违反了基本的设计原则,并对设计质量产生负面影响。”(来自“重构软件设计异味:管理技术债务”)
有许多根据违反设计原则分类的设计异味: 抽象异味 缺失抽象:当使用数据块或编码字符串而不是创建类或接口时,会出现此异味。 命令式抽象:当将操作转换为类时,会出现此异味。 不完整的抽象:当抽象不完全支持互补或相关的方法时,会出现此异味。 多面抽象:当一个抽象分配了多个责任时,会出现此异味。 不必要的抽象:当在软件设计中引入实际上不需要的抽象时(因此可以避免),会出现此异味。 未使用的抽象:当一个抽象未被使用时(无论是直接未使用还是不可达),会出现此异味。

重复抽象: 当两个或多个抽象具有相同的名称或相同的实现或两者都具有时,会出现这种气味。

封装气味

封装不足: 当一个或多个抽象成员的声明可访问性比实际要求的更宽松时,会出现这种气味。

泄漏封装: 当一个抽象通过其公共接口“暴露”或“泄漏”实现细节时,会出现这种气味。

缺少封装: 当实现变化未在一个抽象或层次结构内进行封装时,会出现这种气味。

未利用封装: 当客户端代码使用显式类型检查(使用链式if-else或switch语句检查对象的类型)而不是利用已经封装在层次结构中的类型变化时,会出现这种气味。

模块化气味

破碎的模块化: 当理想情况下应该被局部化到单个抽象中的数据和/或方法被分离并分散到多个抽象中时,会出现这种气味。

模块化不足: 当存在一个抽象未完全分解,并且进一步分解可以减少其大小、实现复杂性或两者兼而有之时,会出现这种气味。

循环依赖模块化:当两个或多个抽象直接或间接地相互依赖(创建抽象之间的紧密耦合)时,会出现此问题。
中心式模块化:当一个抽象与大量其他抽象存在依赖关系(包括传入和传出)时,会出现此问题。
层次结构异味:
缺失层次结构:当代码段使用条件逻辑(通常与“标记类型”一起使用)来明确管理行为变化时,可能已经可以创建并使用层次结构来封装这些变化。
不必要的层次结构:整个继承层次结构都是不必要的,表明继承已经被不必要地应用于特定的设计上下文。
未因子分解的层次结构:在层次结构中的类型之间存在不必要的重复时,会出现此问题。
宽泛的层次结构:当继承层次结构“过于”宽泛时,表明中间类型可能缺失。
推测性层次结构:当层次结构中的一个或多个类型是根据想象而非真实需求提供的时,会出现此问题。

深度层次结构:当继承层次结构过于“深”时,就会出现这种问题。

叛逆式层次结构:当子类型拒绝其超类型提供的方法时,就会出现这种问题。

破碎的层次结构:当一个超类型及其子类型在概念上不共享“IS-A”关系,导致替代无效时,就会出现这种问题。

多路径层次结构:当一个子类型既直接继承自超类型,又间接继承自同一超类型,从而在继承层次结构中出现不必要的继承路径时,就会出现这种问题。

循环依赖的层次结构: 当一个层次结构中的超类型依赖于其任何子类型时,就会出现这种问题。


上述定义和分类在《软件设计异味重构:管理技术债务》中有描述。更多相关资源可以在这里找到。

55

模式是解决某一类问题的一种思想。反模式则是不能用来解决问题的思想,因为实施该思想会导致糟糕的设计。

例如:使用函数进行代码复用是一种“模式”,而使用复制粘贴则是一种“反模式”。这两种方法都可以解决同样的问题,但使用函数通常比复制粘贴更容易阅读和维护。


20

反模式是一种不解决问题的方式。但这还不够:它也是在试图解决问题时经常出现的一种方式。


17

如果你真的想学习反模式,可以获取这本书AntiPatterns(ISBN-13:978-0471197133)。

在其中,他们定义了“反模式是一种文学形式,用来描述一个常见问题的解决方案,但却会产生明显的负面后果。”

所以,如果它是一种糟糕的编程实践,但不常见,频率有限,它就不符合反模式定义中的“模式”部分。


1
我不同意你对“共同”的解释。在一个公司、个人或应用程序中,仍然可以找到共同的解决方案或模式。一个问题可能是特定于该公司的,但这并不意味着它是不好的,循环解决方案也不是反模式。 - pabrams
1
@pabrams 我明白你的意思,一个高产的程序员可以使一种模式变得普遍,但只是在局部范围内。我会修改答案。 - kmarsh

12
与设计模式类似,反模式也是一种模板和可重复解决某些问题的方法,但是采用的方式不够优化和有效。

8

有趣的是,解决问题的一种方式既可以是模式,也可以是反模式。单例模式就是这方面的典型例子。它会出现在两种文献中。


1
设计模式不会杀死人,是人们杀死人;)反模式也被认为是一种用于错误目的的好模式,在这种情况下它就成为了反模式。单例模式是一个很好的模式,但如果你使用它来获得一个单一的数据库实例,那么它就变成了反模式。 - Yogurtu

7

反模式(anti-pattern)设计模式(design pattern) 的补充。反模式是在某种情况下不应该使用的通用解决方案。


7
一种常见的制造混乱的方法。例如像神/厨房水槽类(做所有事情)这样的类。

6
今天,软件工程研究人员和从业者经常将“反模式”和“坏味道”互换使用。然而,它们在概念上并不相同。维基百科关于反模式的条目指出,反模式与不良实践或不好的想法至少有两个因素不同。反模式是:“通常使用的过程、结构或行动模式,尽管最初看起来是对问题的一个适当和有效的响应,但通常会带来更多的坏结果而不是有益的结果。” 明确指出反模式被选择是因为认为它是解决所提出的问题的好方法(作为一种模式); 然而,它会带来更多的负面影响而非好处。另一方面,坏味道只是负面影响软件系统质量的不良实践。例如,单例模式是反模式,而上帝类(或不充分模块化)是设计上的坏味道。

我认为上帝类更像是反模式而不是代码异味。此外,“单例”并不是一个很好的反模式示例,如果它真的可以被视为反模式的话。 - pabrams

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