我正在研究模式和反模式。我对模式有一个清晰的概念,但我没有反模式。来自网络和维基百科的定义让我很困惑。
有人能用简单的话给我解释一下什么是反模式吗?目的是什么?他们做什么?这是好事还是坏事?
我正在研究模式和反模式。我对模式有一个清晰的概念,但我没有反模式。来自网络和维基百科的定义让我很困惑。
有人能用简单的话给我解释一下什么是反模式吗?目的是什么?他们做什么?这是好事还是坏事?
当前回答
有趣的是,解决问题的特定方法可以是模式也可以是反模式。单例就是最好的例子。它将出现在两套文学作品中。
其他回答
有趣的是,解决问题的特定方法可以是模式也可以是反模式。单例就是最好的例子。它将出现在两套文学作品中。
因为模式是被发现的,而不是被创造出来的,Allen Holub,这种发现是通过重复发生的;如果我们发现了一个解决特定问题的模式,但不是根据领域专家的知识和经验以正确的方式解决的——我们倾向于称其为反模式
模式:解决常见的、反复出现的问题的正确方法。 反it模式:不是解决常见的、反复出现的问题的正确方法。 这两种方法都是基于最新的知识
和…昨天的有害实践就是明天的反模式Neal Ford,持续交付的工程实践
DevOps世界示例
它曾经是一个最佳实践(构建共享资源)
但在云世界中,当我们在云中管理资源时,它引入了耦合。
所以现在我们倾向于基于解耦或解耦来构建我们的设计
因此,对于特定的领域,例如DevOps:
过去: 共享资源== pattern ==好事 礼物: 共享资源==反模式==坏事 解耦==模式==好事
总之
更喜欢模式而不是反模式
图片来源:Neal Ford,持续交付工程实践
模式是关于如何解决某个类的问题的想法。反模式是一种如何不解决问题的思想,因为实现这种思想将导致糟糕的设计。
举个例子:“模式”是使用一个函数来实现代码重用,“反模式”是使用复制-粘贴来实现相同的功能。两者都解决了同样的问题,但是使用函数通常会比复制粘贴更具有可读性和可维护性。
反模式是软件开发中被认为是糟糕编程实践的某些模式。
设计模式是解决常见问题的常用方法,已经形式化,通常被认为是一种很好的开发实践,与之相反,反模式是不可取的。
例如,在面向对象编程中,思想是将软件分割成称为对象的小块。面向对象编程中的反模式是一个上帝对象,它执行许多功能,最好将这些功能分离到不同的对象中。
例如:
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的模块化:当一个抽象与大量其他抽象具有依赖关系(包括传入和传出)时,就会出现这种气味。
层次结构的气味
缺少层次结构:当代码段使用条件逻辑(通常与“标记类型”结合在一起)显式管理行为中的变化时,就会出现这种气味,而在这种情况下,可以创建层次结构并用于封装这些变化。
不必要的层次结构:当整个继承层次结构都是不必要的时,就会出现这种气味,这表明在特定的设计上下文中不必要地应用了继承。
未分解层次结构:当层次结构中的类型之间存在不必要的重复时,就会产生这种气味。
广泛的层次结构:当继承层次结构“太”宽,表明中间类型可能缺失时,就会出现这种气味。
投机层次结构:当一个层次结构中的一个或多个类型被投机地提供(即,基于想象的需求而不是真实的需求)时,这种气味就会出现。
深层层次结构:当继承层次结构“过度”深时,就会产生这种气味。
叛逆层次:当子类型拒绝其超类型提供的方法时,就会出现这种味道。
破碎的层次结构:当超类型及其子类型在概念上不共享“IS- a”关系,导致可替代性破碎时,就会出现这种气味。
多路径层次结构:当子类型直接或间接地继承超类型,导致层次结构中出现不必要的继承路径时,就会产生这种气味。
循环层次结构:当层次结构中的超类型依赖于它的任何子类型时,就会出现这种气味。
上面的定义和分类在“软件设计气味的重构:管理技术债务”中有描述。更多相关的资源可以在这里找到。