我正在研究模式和反模式。我对模式有一个清晰的概念,但我没有反模式。来自网络和维基百科的定义让我很困惑。
谁能用简单的话向我解释什么是反模式?什么目的?他们在做什么?这是坏事还是好事?
我正在研究模式和反模式。我对模式有一个清晰的概念,但我没有反模式。来自网络和维基百科的定义让我很困惑。
谁能用简单的话向我解释什么是反模式?什么目的?他们在做什么?这是坏事还是好事?
反模式是软件开发中被认为是不良编程实践的某些模式。
与设计模式相反,设计模式是解决常见问题的常用方法,并且通常被认为是一种良好的开发实践,反模式是相反的并且是不可取的。
例如,在面向对象的编程中,想法是将软件分成称为对象的小块。面向对象编程中的反模式是一个上帝对象,它执行许多功能,这些功能可以更好地分离到不同的对象中。
例如:
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() {}
}
底线是使用常用模式(设计模式)开发软件的好方法,但也有一些开发和实现软件的方法可能会导致问题。被认为是不良软件开发实践的模式是反模式。
每当我听到反模式时,我都会想起另一个术语,即。设计气味。
“设计气味是设计中的某些结构,表明违反了基本设计原则并对设计质量产生负面影响”。(来自“软件设计气味的重构:管理技术债务”)
有许多基于违反设计原则的设计气味分类:
抽象的气味
缺少抽象:当使用数据块或编码字符串而不是创建类或接口时,就会产生这种气味。
命令式抽象:当一个操作变成一个类时,就会产生这种味道。
不完全抽象:当抽象不完全支持互补或相互关联的方法时,就会出现这种气味。
多方面的抽象:当一个抽象有多个职责分配给它时,就会产生这种气味。
不必要的抽象:当在软件设计中引入实际上不需要(因此可以避免)的抽象时,就会出现这种气味。
未使用的抽象:当一个抽象未使用(未直接使用或不可访问)时,就会出现这种气味。
重复抽象:当两个或多个抽象具有相同的名称或相同的实现或两者兼而有之时,就会出现这种气味。
封装气味
封装缺陷:当抽象的一个或多个成员的声明可访问性比实际要求的更宽松时,就会出现这种气味。
泄漏封装:当抽象通过其公共接口“暴露”或“泄漏”实现细节时,就会出现这种气味。
缺少封装:当实现变体未封装在抽象或层次结构中时,就会出现这种气味。
未利用的封装:当客户端代码使用显式类型检查(使用链式 if-else 或 switch 语句来检查对象的类型)而不是利用已经封装在层次结构中的类型的变化时,就会出现这种气味。
模块化的气味
模块化损坏:当理想情况下应该本地化到单个抽象中的数据和/或方法被分离并分布在多个抽象中时,就会出现这种气味。
模块化不足:当存在尚未完全分解的抽象时,就会出现这种气味,进一步分解可能会减小其大小、实现复杂性或两者兼而有之。
循环依赖模块化:当两个或多个抽象直接或间接相互依赖(在抽象之间创建紧密耦合)时,就会产生这种气味。
Hub-Like Modularization:当一个抽象与大量其他抽象具有依赖关系(传入和传出)时,就会出现这种气味。
等级制度的味道
Missing Hierarchy:当代码段使用条件逻辑(通常与“标记类型”结合使用)来显式管理行为变化时,就会产生这种气味,而层次结构可能已经创建并用于封装这些变化。
不必要的层次结构:当整个继承层次结构是不必要的时,就会出现这种气味,这表明对特定设计上下文不必要地应用了继承。
未分解的层次结构:当层次结构中的类型之间存在不必要的重复时,就会产生这种气味。
宽层次结构:当继承层次结构“太”宽表明可能缺少中间类型时,就会出现这种气味。
推测层次结构:当层次结构中的一种或多种类型以推测方式提供时(即基于想象的需求而不是实际需求),就会产生这种气味。
深层次结构:当继承层次结构“过分”深时,就会产生这种气味。
Rebellious Hierarchy:当一个子类型拒绝其超类型提供的方法时,就会产生这种气味。
Broken Hierarchy:当超类型和它的子类型在概念上不共享“IS-A”关系导致可替代性中断时,就会出现这种气味。
多路径层次结构:当子类型直接或间接地从超类型继承时,就会产生这种气味,从而导致层次结构中出现不必要的继承路径。
循环层次结构:当层次结构中的超类型依赖于它的任何子类型时,就会产生这种气味。
上述定义和分类在“重构软件设计气味:管理技术债务”中进行了描述。可以在此处找到更多相关资源。
模式是关于如何解决某个类的问题的想法。反模式是如何不解决它的想法,因为实施该想法会导致糟糕的设计。
一个例子:“模式”将使用函数进行代码重用,“反模式”将使用复制粘贴。两者都解决了同样的问题,但使用函数通常会比复制粘贴更易读和维护。
反模式是一种不解决问题的方法。但还有更多:它也是一种在尝试解决问题时经常可以看到的方法。
如果您真的想学习 AntiPatterns,请获取《AntiPatterns 》一书(ISBN-13:978-0471197133)。
在其中,他们定义了“An AntiPattern 是一种文学形式,它描述了对产生明显负面后果的问题的常见解决方案。”
因此,如果这是一种糟糕的编程实践,但不是一种常见的实践——发生频率非常有限,那么它不符合 AntiPattern 定义的“模式”部分。
就像设计模式一样,反模式也是一个模板,也是解决某个问题的可重复方式,但以非最优和无效的方式。
一种常见的弄乱的方法。例如,像上帝/厨房水槽类(什么都做)。
有趣的是,解决问题的给定方式既可以是模式,也可以是反模式。辛格尔顿就是最好的例子。它将出现在两组文献中。
反模式是设计模式的补充。反模式是在特定情况下不应该使用的模板解决方案。
今天,软件工程研究人员和从业者经常交替使用术语“反模式”和“气味”。但是,它们在概念上并不相同。维基百科的反模式条目指出,反模式与坏做法或坏主意至少有两个不同。反模式是
“一种常用的过程、结构或行动模式,尽管最初看起来是对问题的适当和有效的反应,但通常会产生比有益结果更糟糕的后果。”</p>
它清楚地表明选择反模式是因为它是对所提出问题的良好解决方案(作为模式);然而,它带来的负债多于收益。另一方面,气味只是一种不好的做法,会对软件系统的质量产生负面影响。例如,Singleton 是一种反模式,而上帝类(或 Insufficient Modularization)是一种设计味道。
反模式是人们倾向于以错误方式编程的常见方式,或者至少是不太好的方式。
当您以非法方式滥用设计模式,或者您不知道它的实际用法时,有时会使用它。例如,使用简单类的构建器模式,或者为您在代码中使用的每个 Active 类定义一个单例实例。
它也可能超出设计模式。例如,在 Java 中将局部变量定义为 final,或者NullPointerException
在您可以简单地检查输入是否为空时使用 try/catch,或者在使用您没有注意到的对象之后将其清空(就像您在其他一些语言中所做的那样)关于垃圾回收机制,或者调用system.gc()
让内存清空,还有很多其他的误解,很可能被认为是 Cargo-Cult 现象。
在基于微服务的领域:
一切都是微观的,除了数据是一种反模式。这意味着如果每件事都被合理地分解并完全基于 DevOps 和 CI/CD。也许一些分布式设计模式已经到位,甚至完全复制,但所有服务背后都有一个巨大的数据存储,所以它仍然是一个单体数据结构。
任何对给定软件开发环境弊大于利的设计模式都将被视为反模式。
一些反模式是显而易见的,但有些则不是。例如 Singleton,尽管许多人认为它是很好的旧设计模式,但也有其他人不这么认为。
你可以检查单例有什么不好的问题?以便更好地了解对此的不同意见。