什么是反模式?

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

有人能用简单的话给我解释一下什么是反模式吗?目的是什么?他们做什么?这是好事还是坏事?

108353 次浏览

模式是关于如何解决某个类的问题的想法。反模式是一种如何不解决问题的思想,因为实现这种思想将导致糟糕的设计。

举个例子:“模式”是使用一个函数来实现代码重用,“反模式”是使用复制-粘贴来实现相同的功能。两者都解决了同样的问题,但是使用函数通常会比复制粘贴更具有可读性和可维护性。

反模式是软件开发中的某些模式,被认为是糟糕的编程实践。

设计模式是解决常见问题的常用方法,已经形式化,通常被认为是一种很好的开发实践,与之相反,反模式是不可取的。

例如,在面向对象编程中,思想是将软件分割成称为对象的小块。面向对象编程中的反模式是上帝的对象,它执行许多函数,最好将这些函数分离到不同的对象中。

例如:

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

底线是有很好的方法来开发常用模式的软件(设计模式),但也有软件开发和实现的方法可能会导致问题。被认为是糟糕的软件开发实践的模式是反模式。

这是制造混乱的常见方法。例如,god/厨房墨水类(做所有事情)。

反模式是一种不解决问题的方法。但它还有更多的含义:在解决问题的尝试中,它也是一种经常出现的方法。

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

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

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

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

有趣的是,解决问题的特定方法可以是模式也可以是反模式。单例就是最好的例子。它将出现在两套文学作品中。

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

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

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

根据违反设计原则,有许多设计气味分类:

抽象的气味

当使用数据块或编码字符串而不是创建类或接口时,这种气味就会出现。

必要的抽象:当一个操作被转换为一个类时,会产生这种气味。

当一个抽象不完全支持互补或相互关联的方法时,这种味道就会出现。

当一个抽象有多个责任分配给它时,这种气味就会出现。

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

闲散抽象:当一个抽象未被使用(要么没有直接使用,要么无法到达)时,就会出现这种气味。

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

封装的气味

缺乏封装:当抽象的一个或多个成员声明的可访问性比实际需要的更允许时,就会发生这种气味。

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

失踪的封装:当实现变量没有封装在抽象或层次结构中时,会发生这种气味。

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

模块化的气味

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

模块化不足:当一个抽象还没有被完全分解时,这种气味就会出现,而进一步的分解可以减少它的大小,实现的复杂性,或两者兼有。

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

枢纽模块化:当一个抽象与大量其他抽象有依赖关系(包括传入和传出)时,这种气味就会出现。

层次结构的气味

失踪的层次结构:当代码段使用条件逻辑(通常与“标记类型”结合在一起)显式管理行为中的变化时,这种气味就会出现,其中可以创建层次结构并用于封装这些变化。

不必要的层次结构:当整个继承层次结构是不必要的时,这种气味就会出现,表明继承已经不必要地应用于特定的设计上下文中。

当层次结构中的类型之间存在不必要的重复时,就会出现这种气味。

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

当一个层次结构中的一个或多个类型被投机性地提供(即,基于想象的需求而不是真实的需求)时,这种气味就会出现。

当继承层次“过度”深时,会出现这种气味。

当子类型拒绝其超类型提供的方法时,会出现这种气味。

当超类型和它的子类型在概念上不共享“IS- a”关系,导致可替代性被破坏时,就会出现这种气味。

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

当层次结构中的超类型依赖于它的任何子类型时,就会出现这种气味。


上述定义和分类在“软件设计的重构:管理技术债务中描述。一些更相关的资源可以找到在这里

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

今天,软件工程研究人员和实践者经常互换使用术语“反模式”和“气味”。然而,它们在概念上并不相同。维基百科上关于反模式的条目指出,反模式与坏实践或坏想法至少有两个不同之处。反模式是

"一种常用的过程、结构或行为模式 最初看起来是对一种疾病的适当而有效的反应

另一方面,气味只是一种糟糕的做法,它会对软件系统的质量产生负面影响。例如,Singleton是一种反模式,God类(或不足模块化)是一种设计气味。

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

有些反模式是明显的,有些则不是。例如,单例,尽管许多人认为这是一个很好的旧设计模式,但也有其他人不这么认为。

你可以检查问题单身有什么不好呢?,以更好地了解对它的不同意见。

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

它也可能超出了设计模式。例如,在Java中将局部变量定义为final,或者在你可以简单地检查输入是否为空时使用try / catch NullPointerException,或者在使用对象(就像你在其他一些语言中所做的那样)后将其置空,而你没有注意到垃圾收集机制,或者调用system.gc()使内存为空,以及许多其他误解,这些很可能被认为是Cargo-Cult现象。

在基于微服务的领域:

一切都是微观的,除了数据是反模式。 它是指基于DevOps和CI/CD对每一件事情进行合理、充分的分解。也许一些分布式设计模式已经到位,甚至完全复制,但所有服务背后都有一个巨大的数据存储,因此它仍然是一个单一的数据结构

Microservices反模式的另一个例子

因为模式被发现没有被创建艾伦Holub,这个发现是通过重复发生的;如果我们发现了一个解决特定问题的模式,但不是根据领域专家的知识和经验以正确的方式-我们倾向于称其为反模式

模式:解决一个常见的、反复出现的问题的正确方法。
anit-pattern:不是解决一个常见的,反复出现的问题的正确方法。
这两种方法都是基于最新的知识

和…昨天的有害行为就是明天的反模式尼尔·福特,持续交付工程实践

DevOps世界示例

它曾经是一个最佳实践(构建共享资源)

enter image description here

但是在世界中,当我们在云中管理资源时,它引入了耦合

所以现在我们倾向于基于解耦分开Uncoupling•Michael Nygard•GOTO 2018来构建我们的设计

因此,对于特定的领域,例如DevOps:

< p >:
共享资源== 模式 ==好东西
礼物:
共享资源== 反模式 ==不好的事情
解耦== 模式 ==好事

总之

更喜欢模式而不是反模式


图片来源:Neal Ford,持续交付工程实践