什么是反模式?

Posted

技术标签:

【中文标题】什么是反模式?【英文标题】:What is an anti-pattern? 【发布时间】:2010-11-02 02:37:53 【问题描述】:

我正在研究模式和反模式。我对模式有一个清晰的概念,但我没有反模式。来自网络和***的定义让我很困惑。

谁能用简单的话向我解释一下目的是什么?他们在做什么?这是好事还是坏事?

【问题讨论】:

sourcemaking.com/antipatterns martinfowler.com/bliki/AntiPattern.html C2 wiki——Ward Cunningham 的原始 wiki 站点——有很多关于编程模式的资料,还有一个关于 AntiPatterns 的页面。 (如果您不熟悉该网站的概念设计,可能首先访问起始页。它与如今人们认为的“wiki”含义相去甚远,尽管它显然启发了 Wikipedia 和 Wikia 等平台的架构。) 【参考方案1】:

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

与design patterns 不同,design patterns 是解决常见问题的常用方法,并且通常被认为是一种良好的开发实践,而反模式则相反并且是不可取的。

例如,在面向对象的编程中,其思想是将软件分成称为对象的小块。面向对象编程中的一种反模式是God object,它执行了许多可以更好地分离到不同对象中的功能。

例如:

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() 

最重要的是,有一些很好的方法可以使用常用模式 (design patterns) 来开发软件,但也有一些开发和实施软件的方法可能会导致问题。被认为是不良软件开发实践的模式是反模式。

【讨论】:

除了GodObject还有其他反模式的例子吗? @Tomasz Programming Pasta serving 就是这样一个例子。最好将其概括为许多小对象之间的不良封装。认为它是上帝对象的对立面en.wikipedia.org/wiki/Spaghetti_code @Tomasz 任何不好但由某些人完成的事情都是反模式。例如,try: <do something>; except: pass 可能是 Python 中的 Cardinal Sin 反模式。看到这个:realpython.com/blog/python/… 单例是否可以被认为是一种反模式,因为它使得并行模拟和运行测试变得更加困难(因为所有测试都使用和变异相同的单例,从而导致不一致)? @lostsoul29 这取决于您的程序的最终目的是否是并行测试的能力......(在您提到的特定情况下:这是一个应该纠正或记录的可重入问题)。单例一种模式,应该用于它擅长的领域。【参考方案2】:

每当我听到反模式时,我都会想起另一个术语,即。设计气味。

“设计异味是设计中的某些结构,表明违反了基本设计原则并对设计质量产生负面影响”。(摘自“软件设计异味的重构:管理技术债务”)

有许多基于违反设计原则的设计气味:

抽象气味

缺少抽象:当使用数据块或编码字符串而不是创建类或接口时,就会产生这种味道。

命令式抽象:当一个操作变成一个类时,就会产生这种味道。

不完整的抽象:当抽象不完全支持互补或相互关联的方法时,就会产生这种味道。

多方面抽象:当一个抽象有多个职责分配给它时,就会产生这种味道。

不必要的抽象:当在软件设计中引入实际上不需要(因此可以避免)的抽象时,就会出现这种气味。

未使用的抽象:当抽象未使用(未直接使用或无法访问)时,就会产生这种气味。

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

封装气味

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

泄漏封装:当抽象通过其公共接口“暴露”或“泄漏”实现细节时,就会产生这种味道。

缺少封装:当实现变体未封装在抽象或层次结构中时,就会出现这种气味。

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

模块化的味道

破碎的模块化:当理想情况下应该本地化到单个抽象中的数据和/或方法被分离并分布在多个抽象中时,就会产生这种味道。

模块化不足:当存在尚未完全分解的抽象时,就会产生这种味道,而进一步分解可能会减小其大小、实现复杂性或两者兼而有之。

循环依赖模块化:当两个或多个抽象直接或间接相互依赖(在抽象之间创建紧密耦合)时,就会产生这种味道。

Hub-Like Modularization:当一个抽象与大量其他抽象具有依赖关系(传入和传出)时,就会产生这种味道。

层次结构的味道

缺少层次结构: 当代码段使用条件逻辑(通常与“标记类型”结合使用)来显式管理行为变化时,就会产生这种气味,其中层次结构可能已被创建并用于封装这些变化。

不必要的层次结构:当整个继承层次结构是不必要的时,就会产生这种味道,表明对特定设计上下文不必要地应用了继承。

未分解的层次结构:当层次结构中的类型之间存在不必要的重复时,就会产生这种气味。

宽层次结构:当继承层次结构“太”宽表明可能缺少中间类型时,就会产生这种气味。

推测层次结构:当层次结构中的一种或多种类型以推测方式提供时(即基于想象的需求而不是实际需求),就会产生这种气味。

深层次结构:当继承层次结构“过分”深时,就会产生这种味道。

Rebellious Hierarchy:当子类型拒绝其超类型提供的方法时,就会产生这种气味。

Broken Hierarchy:当超类型和它的子类型在概念上不共享“IS-A”关系导致可替换性中断时,就会产生这种气味。

多路径层次结构:当子类型直接或间接继承自超类型导致层次结构中不必要的继承路径时,就会产生这种气味。

循环层次结构:当层次结构中的超类型依赖于它的任何子类型时,就会产生这种气味。


上面的定义和分类在"Refactoring for software design smells: Managing technical debt"中有描述。更多相关资源可以在here找到。

【讨论】:

【参考方案3】:

模式是关于如何解决某个类的问题的想法。反模式是关于如何不解决它的想法,因为实施该想法会导致糟糕的设计。

一个例子:“模式”是使用函数来重用代码,“反模式”是使用复制粘贴。两者都解决了同样的问题,但使用函数通常会比复制粘贴更易读和维护。

【讨论】:

【参考方案4】:

反模式是一种不解决问题的方法。但还有更多:这也是一种在尝试解决问题时经常可以看到的方法。

【讨论】:

【参考方案5】:

如果您真的想学习 AntiPatterns,请获取AntiPatterns一本书(ISBN-13:978-0471197133)。

在其中,他们定义“An AntiPattern 是一种文学形式,它描述了对产生明显负面后果的问题的常见解决方案。”

因此,如果这是一种糟糕的编程实践,但不是一种常见的实践——发生频率非常有限,则它不符合 AntiPattern 定义的“模式”部分。

【讨论】:

我不同意你对“普通”的解释。您仍然可以在公司的个人或应用程序中找到常见的解决方案或模式。问题可能是该公司独有的,但这并不意味着其糟糕的、经常出现的解决方案不是反模式。 @pabrams 我明白你的意思,一个多产的程序员可以使一种模式变得通用,即使只是在本地。我会修改答案。【参考方案6】:

就像一个设计模式,一个反模式也是一个模板和解决某个问题的可重复的方式,但是在一个非最优和无效的方式。

【讨论】:

【参考方案7】:

有趣的是,解决问题的既定方式既可以是一种模式,也可以是一种反模式。辛格尔顿就是最好的例子。它会出现在两组文献中。

【讨论】:

【参考方案8】:

一种常见的弄乱的方法。例如,像 god/kitchensink 类(什么都做)。

【讨论】:

【参考方案9】:

反模式设计模式的补充。反模式是在特定情况下不应该使用的模板解决方案。

【讨论】:

【参考方案10】:

如今,软件工程研究人员和从业者经常交替使用“反模式”和“气味”这两个术语。但是,它们在概念上并不相同。***的反模式条目指出,反模式与坏做法或坏主意的区别至少有两个因素。反模式是

“一种常用的过程、结构或行为模式,尽管 最初似乎是对 问题,通常会带来比有益结果更糟糕的后果。”

它清楚地表明选择反模式是因为相信它是所提出问题的良好解决方案(作为模式);但是,它带来的弊大于利。另一方面,气味只是一种不好的做法,会对软件系统的质量产生负面影响。例如,Singleton 是一种反模式,而上帝类(或 Insufficient Modularization)是一种设计味道。

【讨论】:

我会说上帝类与其说是一种气味,不如说是一种反模式。此外,“单例”不是反模式的一个很好的例子。如果它甚至可以被认为是一种反模式,那么。【参考方案11】:

反模式是人们倾向于以错误方式编程的常见方式,或者至少是不太好的方式。

【讨论】:

【参考方案12】:

当您以非法方式滥用设计模式,或者您不知道它的实际用法时,有时会使用它。例如,为简单的类设置构建器模式,或者为您在代码中使用的每个 Active 类定义一个单例实例。

它也可能超出设计模式。例如,在 Java 中将局部变量定义为 final,或者在您可以简单地检查输入是否为 null 时使用 try / catch 来处理 NullPointerException,或者在使用对象后将其清空(就像您在某些其他语言中所做的那样) '不注意垃圾回收机制,或者调用system.gc()清空内存等许多误解,很可能被认为是Cargo-Cult现象。

【讨论】:

【参考方案13】:

在基于微服务的领域:

一切都是微观的,除了数据是一种反模式。 这意味着如果每件事都被合理地分解并完全基于 DevOps 和 CI/CD。也许一些分布式设计模式已经到位,甚至完全复制,但所有服务背后都有一个巨大的数据存储,所以它仍然是一个单体数据结构。

Other example of Microservices anti-pattern

【讨论】:

【参考方案14】:

任何对给定软件开发环境弊大于利的设计模式都将被视为反模式。

有些反模式是显而易见的,但有些则不是。例如 Singleton,尽管许多人认为它是很好的旧设计模式,但也有其他人不这么认为。

您可以查看问题What is so bad about singletons?以更好地了解对此的不同意见。

【讨论】:

实际上,反模式通常并不明显。显然,糟糕的设计模式就是糟糕的设计模式。真正的反模式在表面上看起来是站得住脚的,但后来会出现问题。事实上,不明显是坏的就是让它们首先成为反模式的区别。

以上是关于什么是反模式?的主要内容,如果未能解决你的问题,请参考以下文章

为啥 Singleton 被认为是反模式? [复制]

ServiceLocator 是反模式吗?

关于“贫血领域模型”被认为是反模式[闭合]的具体例子

INTERPRETER 是反模式吗?

深度嵌套字典是反模式吗?

像isInUnitTest()这样的检查是反模式吗?