devise模式避免
很多人似乎都认同,Singleton模式有许多缺点,甚至有人build议完全避免模式。 这里有一个很好的讨论 。 请指出关于Singleton模式的任何意见。
我的问题 :是否有其他devise模式,应该避免或小心使用?
模式很复杂
所有的devise模式都应该谨慎使用。 在我看来,如果有一个合理的理由,而不是立即执行一个模式, 你应该重新对模式进行重构 。 使用模式的一般问题是增加了复杂性。 过度使用模式会使给定的应用程序或系统进一步发展和维护繁琐。
大多数时候,有一个简单的解决scheme,你不需要应用任何特定的模式。 一个好的经验法则就是在代码片段被replace或需要经常更改时使用模式,并准备在使用模式时处理复杂代码的警告。
记住你的目标应该是简单的,并且如果你看到一个实际的需要支持你的代码的改变的话,就应该使用一个模式
模式原则
如果他们显然可能导致过度devise和复杂的解决scheme,那么使用模式可能看起来是没有意义的。 然而,程序员阅读大部分模式的基础devise技术和原理更为有趣。 事实上,我最喜欢的一本关于“devise模式”的书籍强调了这个问题 ,重申了哪些原则适用于所讨论的模式。 就相关性而言,它们很简单,比模式更有用。 一些原则通常足以涵盖超过面向对象的编程(OOP),比如Liskovreplace原则 ,只要你可以构build你的代码模块。
有许多devise原则,但在GoF书第一章中描述的那些原则是非常有用的。
- 编程到一个“接口”,而不是“实现”。 (四人帮1995:18)
- 赞成“对象组合”而不是“类inheritance”。 (四人帮1995:20)
让那些沉没在你身上一段时间。 应该注意的是,当写入GoF时, 接口意味着什么是抽象(也就是超类),不要将其与接口混为一体,成为Java或C#中的types。 第二个原则来自观察到的过度使用inheritance,这在今天仍然是常见的 。
从那里你可以读到罗伯特·塞西尔·马丁( Robert Cecil Martin) (也就是鲍勃叔叔) 所说的固体原理 。 斯科特·汉塞尔曼(Scott Hanselman)在一个关于这些原则的播客中采访了鲍勃叔叔:
- 单一的责任原则
- O笔closures原则
- L iskov替代原则
- 我接口的隔离原则
- 依赖倒置原则
这些原则是一个很好的开始阅读和与同龄人讨论。 您可能会发现这些原则相互交织,并与其他过程(如关注点分离和dependency injection)相互交织。 在进行TDD一段时间之后,您也可能会发现这些原则在实践中是自然而然的,因为您需要在某种程度上遵循这些原则才能创build单独的和可重复的unit testing。
devise模式的作者自己最担心的是“访问者”模式。
这是一个“必要的邪恶” – 但是经常被过度使用,而且对它的需求经常会在你的devise中出现一个更根本的缺陷。
“Visitor”模式的另一个名称是“Multi-dispatch”,因为当您希望使用单一types的调度OO语言来select要使用的代码时,Visitor模式就是您最终使用的模式(或更多)不同的对象。
典型的例子是你有两个形状的交集,但是有一个更简单的情况经常被忽视:比较两个异构对象的相等性。
无论如何,通常你会得到这样的结果:
interface IShape { double intersectWith(Triangle t); double intersectWith(Rectangle r); double intersectWith(Circle c); }
这个问题是你把所有的“IShape”的实现联系在一起的。 您已经暗示,只要您希望将新形状添加到层次结构中,就需要更改所有其他“形状”实现。
有时候,这是一个正确的最小devise – 但想一想。 你的devise真的要求你需要派遣两种types? 你是否愿意写出多种方法的组合爆炸?
通常,通过引入另一个概念,您可以减less实际需要编写的组合的数量:
interface IShape { Area getArea(); } class Area { public double intersectWith(Area otherArea); ... }
当然,这取决于 – 有时你确实需要编写代码来处理所有这些不同的情况 – 但是在冒险和使用Visitor之前,有必要暂停一下并思考一下。 这可能会在以后为你节省很多痛苦。
单身人士 – 一个使用单身人士X的类对它有依赖性,很难看清楚,很难隔离进行testing。
它们经常被使用,因为它们方便易懂,但是它们会使testing变得复杂。
见单身人士是病理性说谎者 。
我相信模板方法模式通常是一个非常危险的模式。
- 很多时候,它会因为“错误的原因”而使用inheritance层次结构。
- 基类有倾向于散布各种不相关的代码。
- 它迫使你lockingdevise,通常在开发过程中很早。 (在很多情况下过早locking)
- 稍后改变这一点变得越来越困难。
我不认为你应该避免devise模式(DP),我不认为你应该强制自己在规划你的架构时使用DP。 当我们从规划中自然出现时,应该只使用DP。
如果我们从一开始就定义要使用给定的DP,那么我们未来的许多devise决策就会受到这个select的影响,而不能保证我们select的DP是否适合我们的需求。
有一件事我们也不应该把DP当作一个不可变的实体,我们应该把模式适应我们的需要。
因此,我想我们应该避免DP,当我们的build筑已经形成时,我们应该拥抱他们。
我认为Active Record是一个过度使用的模式,鼓励混合业务逻辑与持久性代码。 从模型层隐藏存储实现并将模型绑定到数据库方面做得并不好。 在数据网关,行数据网关和数据映射器等方面有很多替代scheme(在PoEAA中有描述),它们通常提供了更好的解决scheme,并且有助于提供更好的存储抽象。 另外,你的模型不需要存储在数据库中; 那么把它们存储为XML或使用Web服务访问它们呢? 改变模型的存储机制有多容易?
也就是说,Active Record并不总是很糟糕,对于其他选项过于简单的简单应用来说,它是完美的。
这很简单…避免devise模式不清楚 ,或你不舒服的devise模式。
命名一些…
有一些不切实际的模式 ,例如:
-
Interpreter
-
Flyweight
还有一些难以把握 ,如:
-
Abstract Factory
– 与创build对象的家族完全抽象的工厂模式是不是这样的微风,因为它似乎是 -
Bridge
– 如果抽象和实现被划分为子树,可能会变得太抽象,但在某些情况下是非常实用的模式 -
Visitor
– 双重调度机制的理解是必须的
有一些模式看起来非常简单 ,但由于各种原因与其原理或实施有关的原因, 并不是很明确的select :
-
Singleton
– 不是完全不好的模式,只是过度使用(通常在那里,它不适合) -
Observer
– 伟大的模式…只是使代码更难以阅读和debugging -
Prototype
– 交易编译器检查活力(可以是好的或坏的…取决于) -
Chain of responsibility
– 往往只是被强迫/人为地推入devise中
对于那些“不切实际的人”,在使用它们之前应该真正考虑一下,因为在某个地方通常会有更优雅的解决scheme。
对于“难以掌握”的人来说……当他们在适当的地方使用,并且执行的很好的时候,他们真的是很大的帮助,但是当他们使用不当时,他们是噩梦。
现在,接下来是…
- 首先devise模式是必须的
- 来源是“急救”
我希望我不会为此而挨打。 克里斯特·爱立信在其实时碰撞检测博客中撰写了两篇有关devise模式主题的文章(1,2篇)。 他的语气相当苛刻,也许有点挑衅,但是这个人知道他的东西,所以我不会把它当作一个疯子的狂言。
有人说服务定位器是反模式。
我相信观察者模式有很多可以回答的问题,它在很普通的情况下工作,但是随着系统变得越来越复杂,它需要OnBefore(),OnAfter()通知,并且经常发布asynchronous任务,入性。 一个更好的解决scheme是开发一个自动依赖关系分析系统,它在计算过程中处理所有对象访问(具有读取障碍),并在依赖关系图中自动创build边。
对Spoike的文章“ Refactoring to Patterns ”的补充是一个很好的阅读。
迭代器是一个可以避免的GoF模式,或者至less只有在没有可用的替代方法时才使用它。
替代scheme是:
-
为每个循环。 这种结构在大多数主stream语言中都存在,在大多数情况下可以用来避免迭代器。
-
select器LINQ或jQuery。 应该使用它们,因为不是所有的容器对象都应该被处理。 与迭代器不同,select器允许在一个地方显示要处理的对象types。