滥用设计模式

时间:2008-10-30 21:05:44

标签: design-patterns oop anti-patterns

在规范的四人小组列表中,是否存在您经常发现误用,误解或过度使用的任何设计模式(除了备受争议的Singleton之外)?换句话说,有没有一种设计模式,建议您在使用前三思而后行? (为什么?)

15 个答案:

答案 0 :(得分:17)

单身人士模式.. 全局状态通常会在测试时导致问题

任何依赖单例的代码都会变得越来越难以测试,因为这种依赖关系不容易被嘲笑..

答案 1 :(得分:15)

工厂模式......

我被空降到一个项目之前,系统中的每个MyObject都有一个等效MyObjectFactory来生成新实例。没有抽象或扩展类的概念......只是简单的旧ClassX& ClassXFactory。

没有人可以解释为什么......“这就是事情一直以来的方式”

答案 2 :(得分:9)

唯一的一个(除了前面提到的Singleton及其犯罪伙伴,工厂)不会是一个GoF,它应用于对象的原生属性时的设置者和吸气剂。

应用于成员变量的setter和getter在功能上与public成员变量相同。没有setter的getter更像是一个公共最终成员变量 - 但是在那时为什么不只是使用一个公共最终成员变量,它们不会造成更多伤害......

唯一的区别是你“可以”拦截电话并覆盖它,但人们很少这样做。更常见的是,它被用作程序程序员的拐杖,以避免OO编程(这是反模式的真正原因)。

使用setter和/或getter,你仍然会将内部成员结构暴露给外部世界(例如,如果你发现需要将int更改为long,则必须重构其他类)几乎可以确保应该在你的对象中的一些代码放在外面。

我可以想到一些例外:

Setter用于简化对象构造。有时需要创建一个对象,然后再设置其他值。这些值应该是不可变的(你不应该调用set两次)以保证安全。

Getters用于访问包含的对象。由于所包含的对象通常能够确保其自身的完整性,因此共享它们非常有用。在这种情况下,建立者通常很糟糕,你不希望在鼻子下方交换具有特定状态的对象,这使得确保自己的完整性变得更加困难。

用于屏幕组件的Java Bean:是的,无法找到实现这些“属性球”的更好方法。反射对这个组件很方便,模式很有用 - 它有点像hacky但有效。

DAO / DTO Bean对象。老实说,我认为这些是模式的一种不经常使用,但它们是 模式。它通过元数据而非代码操作属性比应该更难,因为它必须是反射的。 bean属性总是与某些外部源(数据库格式,数据传输格式,组件属性......)相关联,那么为什么我们要复制定义每个部分的工作呢?

编辑:从kyoryu的评论中被盗,被带到了帖子,因为它真的是我所说的完美总结,可能会在评论中遗漏。需要,因为不是每个人似乎都认为添加语言的访问器只能编写糟糕的OO设计模式:

短版 -

if (account1.balance > 1000)
{
    account1.balance = account1.balance - 1000;
    account2.balance = account2.balance + 1000;
}; = BAD CODE. 

account2.deposit(account1.withdraw(1000)); = GOOD CODE. 

第二个不需要访问者... - kyoryu (由于账单k略有修改,因为我的评论空间比他的评论多一点)。

第二个将测试和其他一些数学内容移到Account中,而不是在每个可能进行转移的地方将其复制到整个代码中。

只是为了说明问题更多,请注意,使用“GOOD CODE”样式很明显,.withdraw的输出可能是一个Transaction对象,其中包含有关整个事务的信息,包括其成功,源和目标以及日志记录能力。对于以“BAD CODE”风格编写代码的人来说,这会怎样?

另外,你如何重构BAD CODE甚至使用这样的对象?这只是一团糟。

答案 3 :(得分:4)

实际上,我最常看到的是使用适当模式的缺乏。典型情况:我:“嘿,模块A已经有一段代码循环遍历一组对象并对它们执行数据库操作X,为什么不重用那些代码?”编码员:“好吧,但我必须对这些物体进行Y操作。”我:“如果使用重构它来使用Command模式来执行适当的X或Y呢?”

我曾经看到过使用Subject-Observer模式失控。它是在使用数据库持久存储Subject的进程之间实现的。由于主题的更新次数和观察者的数量,数据库的负载非常大,并导致无法预料的系统范围的减速。

答案 4 :(得分:4)

我也会说工厂模式。与Eoin相似的经历。在我的情况下,该项目有大量的工厂,因为有些人认为你可能已经使用对象A进行本地实现,对象B用于远程实现,并且它是通过工厂抽象的(这是一件明智的事情)。

但是,未来从未需要或实施甚至预见到“远程”实施......而且,技能较低的工程师也开始采用这种模式来处理许多其他事情......就像一个千篇一律的人...... p>

答案 5 :(得分:3)

ALL。

不要误解我的意思,我发现它们是一个很好的基础,当得到理解时非常有帮助。获取设计技能需要花费很多时间才能知道何时以及如何在代码中应用它们。实际上,这是创建干净代码技能的总体情况。

它不是没有使用那么,正是你在“使用前三思而后行”的问题中所说的。很好地理解你在做什么以及为什么。如果你不这样做,那就和那些可以指导你的人交谈 - 除了阅读之外。要小心那些知道所有模式的人,但不能清楚地解释他们中的任何一个/为什么 - 特别是那个问题。

答案 6 :(得分:2)

我看到的最重要的是单身模式,其中没有足够的关心和愚蠢应用于如何以及何时应该调用单身人士的析构函数。

对于这种普遍存在的模式,几乎没有任何关于确定单身人士何时必须死亡的正确程序的讨论。

只是我的0.02。

欢呼声,

罗布

答案 7 :(得分:2)

实际上,我认为当KISS( 保持简单,愚蠢保持简短和简单)解决方案就是所需要的时候,一般来说设计模式都会被过度使用。

设计模式非常适合使系统灵活,但代价是使实施更加复杂。当灵活性提供实际优势时,这只是一个值得的权衡。

答案 8 :(得分:2)

如果所有类型的逻辑被整合到一个巨大的类中,Mediator模式肯定有可能被滥用。

答案 9 :(得分:1)

C#中的观察者模式非常无用,因为它有事件。

答案 10 :(得分:1)

我只是想在看到一些“所有模式都不好”的答案之后再添加一条评论。

如果你是一个正在处理中等挑战性问题的程序员,那么几乎所有的模式都应该在某个时刻向你展示作为问题的“明显”解决方案。

“设计模式”一书的唯一真正意义就是将名字放在我们每天都做的事情上,这样我们才能更好地沟通。

我想如果你是一个新手的程序员,那么阅读它们会非常有帮助,这样你需要的那一天就不必自己解决它,它已经在你的工具箱中,但总的来说 - 其中任何一个都可以通过Gang of One(anyOne!)来解决。

如果您还不知道其中任何一项,您可能根本就不需要它。

将名字放在模式中并将它们形式化一点是非常有用的,但我根本就没有抱怨这本书。如果你在这里看不到几乎所有模式的偶然需要,你就不会在非常难的代码上工作(或者你重复代码很多,我认为这是主要的罪行。)

答案 11 :(得分:0)

首先,“它取决于”语言 - 某些语言中的某些结构减少了对某些设计模式的需求。

其次,Design Pattern概念模板的一部分从一开始就包含了“适用性”和“后果”的部分 - 忽略这些,风险自负。 “了解”模式并不仅仅意味着您知道如何使用您选择的语言对其进行编码 - 它还意味着知道何时使用它,以及使用它可能带来哪些缺点。

答案 12 :(得分:0)

仅在需要时使用模式。你无法预测未来,所以虽然你可能会设计一个模式来使设计变得灵活,但当产品采用不同的方向并且你的模式成为阻止你实现用户想要的东西的时候会发生什么?

让设计尽可能简单。当您了解有关设计需要更改的更多信息时,请使用适当的模式,而不是之前。

答案 13 :(得分:0)

存储模式

大多数人在阅读Eric Evans的“领域驱动设计”一书后立即开始使用此模式。

这里有多少人看过构建数据访问对象的存储库?

答案 14 :(得分:0)

您无法直接回答此问题。它主要是主观的,取决于应用要求。

  1. 大多数人都引用Singleton_pattern是不好的,但对每个用户和项目来说都不错。对于我的项目要求,它符合目的。我需要一个ConnectionManager来处理客户端和应用程序之间的会话管理,而Singleton可以很好地完成工作。

  2. 您已经为第三方jar提供了良好的文档。 jar包含继承层次结构。现在你必须为每个孩子添加一个操作。由于您没有源代码,因此您无法执行此操作。现在,您可以使用Visitor_pattern获益。但是如果您有源代码,则可能根本不使用Visitor模式。您可以在父级和每个子级中简单地添加新操作。缺乏源代码并不意味着我滥用Visitor模式。

  3. 我想限制各种对象之间的通信。我将继续使用实现Mediator_pattern进行对象通信。我想限制客户端暴露于我的系统以隐藏复杂性。我将继续Facade_pattern。这并不意味着我滥用这些模式。同样的例子可以扩展到其他模式,如Proxy_pattern等。