有人能简单地向我解释一下反模式吗?它的目的是什么?它们都做些什么?这是好事还是坏事?
反模式(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() {}
}
归根结底,有一些好的方法可以使用常用模式(设计模式)来开发软件,但也有一些开发和实现软件的方式可能会导致问题。 被认为是不良软件开发实践的模式被称为反模式。
重复抽象: 当两个或多个抽象具有相同的名称或相同的实现或两者都具有时,会出现这种气味。
封装气味
封装不足: 当一个或多个抽象成员的声明可访问性比实际要求的更宽松时,会出现这种气味。
泄漏封装: 当一个抽象通过其公共接口“暴露”或“泄漏”实现细节时,会出现这种气味。
缺少封装: 当实现变化未在一个抽象或层次结构内进行封装时,会出现这种气味。
未利用封装: 当客户端代码使用显式类型检查(使用链式if-else或switch语句检查对象的类型)而不是利用已经封装在层次结构中的类型变化时,会出现这种气味。
模块化气味
破碎的模块化: 当理想情况下应该被局部化到单个抽象中的数据和/或方法被分离并分散到多个抽象中时,会出现这种气味。
模块化不足: 当存在一个抽象未完全分解,并且进一步分解可以减少其大小、实现复杂性或两者兼而有之时,会出现这种气味。
循环依赖模块化:当两个或多个抽象直接或间接地相互依赖(创建抽象之间的紧密耦合)时,会出现此问题。深度层次结构:当继承层次结构过于“深”时,就会出现这种问题。
叛逆式层次结构:当子类型拒绝其超类型提供的方法时,就会出现这种问题。
破碎的层次结构:当一个超类型及其子类型在概念上不共享“IS-A”关系,导致替代无效时,就会出现这种问题。
多路径层次结构:当一个子类型既直接继承自超类型,又间接继承自同一超类型,从而在继承层次结构中出现不必要的继承路径时,就会出现这种问题。
循环依赖的层次结构: 当一个层次结构中的超类型依赖于其任何子类型时,就会出现这种问题。
模式是解决某一类问题的一种思想。反模式则是不能用来解决问题的思想,因为实施该思想会导致糟糕的设计。
例如:使用函数进行代码复用是一种“模式”,而使用复制粘贴则是一种“反模式”。这两种方法都可以解决同样的问题,但使用函数通常比复制粘贴更容易阅读和维护。
反模式是一种不解决问题的方式。但这还不够:它也是在试图解决问题时经常出现的一种方式。
如果你真的想学习反模式,可以获取这本书AntiPatterns(ISBN-13:978-0471197133)。
在其中,他们定义了“反模式是一种文学形式,用来描述一个常见问题的解决方案,但却会产生明显的负面后果。”
所以,如果它是一种糟糕的编程实践,但不常见,频率有限,它就不符合反模式定义中的“模式”部分。
有趣的是,解决问题的一种方式既可以是模式,也可以是反模式。单例模式就是这方面的典型例子。它会出现在两种文献中。
反模式(anti-pattern) 是 设计模式(design pattern) 的补充。反模式是在某种情况下不应该使用的通用解决方案。