许多人似乎都认为,单例模式存在一些缺点,有些人甚至建议完全避免使用该模式。在这里有一个很好的讨论。请向那个问题提出任何关于单例模式的评论。
我的问题:是否还有其他设计模式应该避免或者需要格外小心使用?
许多人似乎都认为,单例模式存在一些缺点,有些人甚至建议完全避免使用该模式。在这里有一个很好的讨论。请向那个问题提出任何关于单例模式的评论。
我的问题:是否还有其他设计模式应该避免或者需要格外小心使用?
所有的设计模式都应该谨慎使用。在我看来,您应该有一个有效的理由重构到模式中,而不是马上实现一种模式。使用模式的普遍问题在于它们增加了复杂性。过度使用模式会使给定的应用程序或系统在进一步开发和维护时变得繁琐。
大多数情况下,有一个简单的解决方案,你不需要应用任何特定的模式。一个好的经验法则是,在代码块需要经常被替换或需要经常更改时使用模式,并准备好接受使用模式时带来的复杂代码。
记住,您的目标应该是简单明了, 如果您在代码中看到需要支持更改实际需求,请使用模式。
如果模式显然会导致过度设计和复杂的解决方案,那么使用模式似乎是徒劳的。然而,对于程序员来说,阅读奠定大多数模式基础的设计技术和原则要比使用模式更有趣。事实上,我最喜欢的一本关于“设计模式”的书强调了这一点,重申了适用于相关模式的原则。与模式相关性相比,这些原则足够简单而有用。其中一些原则足以涵盖比面向对象编程(OOP)更广泛的范畴,例如里氏替换原则,只要你能构建代码模块。
有许多���计原则,但《设计模式》的第一章中所描述的原则是一个不错的起点。
《设计模式》一书作者最担心的模式之一是"Visitor"(访问者)模式。
它是一种“必要的恶”,但常常被过度使用,需要使用它通常暴露出你的设计中更根本的缺陷。
"Visitor"模式的另一个名称是“多重派发”,因为当你希望使用单类型派发的面向对象语言基于两个或更多不同对象的类型选择要使用的代码时,就会得到Visitor模式。
其中经典的例子是两个形状的交集,但还有一个更简单的情况经常被忽略:比较两个异构对象的相等性。
总之,通常你会得到类似下面的东西:
interface IShape
{
double intersectWith(Triangle t);
double intersectWith(Rectangle r);
double intersectWith(Circle c);
}
interface IShape
{
Area getArea();
}
class Area
{
public double intersectWith(Area otherArea);
...
}
当然,这取决于情况 - 有时候你确实需要编写代码来处理所有这些不同的情况 - 但在采用访问者模式之前值得暂停和思考一下。这可能会在以后避免很多麻烦。
我认为模板方法设计模式通常是一种非常危险的模式。
这很简单...避免使用你不清楚或者你感觉不舒服的设计模式。
以下是一些例子...
有一些不实用的模式,例如:
解释器
享元
还有一些比较难以理解的模式,例如:
抽象工厂
- 完整的抽象工厂模式和创建对象族的方式并不像看起来那么简单桥接
- 如果将抽象和实现分别划分到子树中,则可能会变得过于抽象,但在某些情况下,这是非常有用的模式访问者
- 必须真正理解双重调度机制还有一些模式看起来非常简单,但由于与其原理或实现相关的各种原因,它们并不是很明显的选择:
单例
- 并不是完全不好的模式,只是被过度使用(经常出现在不适合的地方)观察者
- 很棒的模式...只是让代码变得更难阅读和调试原型
- 交换编译器检查的动态性(这可能是好事或坏事...取决于情况)责任链
- 太经常被强制/人为地推入设计中了对于那些不实用的模式,在使用它们之前,你应该真正考虑一下,因为通常有更优雅的解决方案。
对于比较难以理解的模式,当它们在适当的地方使用并且实现得很好时,它们确实是非常有帮助的...但是如果使用不当,则会成为噩梦。
现在,下一步是什么...
有人认为服务定位器是一种反模式。
我认为观察者模式有很多问题需要解决,它在一般情况下可以工作,但随着系统变得更加复杂,就会变成噩梦,需要 OnBefore()、OnAfter() 通知,并经常发布异步任务以避免重入。一个更好的解决方案是开发一种自动依赖分析系统,在计算过程中对所有对象访问(使用读取屏障)进行仪器化,并自动生成依赖图中的边缘。