20

在典型的“四人帮”列表中,是否有任何您经常发现被滥用、误解或过度使用的设计模式(除了备受争议的 Singleton)?换句话说,您是否建议在使用前三思而后行的设计模式?(为什么?)

4

15 回答 15

17

单例模式..全局状态在测试时经常会导致问题

任何依赖于单例的代码都变得越来越难测试,因为这种依赖不容易被模拟。

于 2008-10-30T21:37:19.923 回答
17

工厂模式...

在此之前,我被空降到一个项目中,系统中的每一个都具有生成新实例MyObject的等价物。MyObjectFactory没有抽象或扩展类的概念......只是普通的旧 ClassX 和 ClassXFactory。

没有人能解释为什么......“这就是事情一直以来的做法”

于 2008-10-30T21:16:47.780 回答
10

唯一的一个(除了前面提到的 Singleton 和它的犯罪伙伴,工厂)不会是 GoF,当应用于对象的本机属性时,它将是 setter 和 getter。

应用于成员变量的 Setter 和 getter 在功能上与公共成员变量相同。没有 setter 的 getter 更像是一个公共的 final 成员变量——但在这一点上,为什么不只使用一个公共的 final 成员变量,它们没有更多的伤害......

唯一的区别是您“可以”拦截呼​​叫并覆盖它,但人们很少这样做。更多时候,它被用作程序程序员避免 OO 编程的拐杖(这是它成为反模式的真正原因)。

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

我能想到的有几个例外:

用于简化对象构造的设置器。有时需要先创建一个对象,然后再设置其他值。为了安全起见,这些值应该是不可变的(您不应该调用 set 两次)。

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

用于屏幕组件的 Java Bean:是的,想不出更好的方法来实现这些“属性球”。反射对于这个组件很方便,模式很有用——它有点老套,但很有效。

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 以使用这样的对象?这只是一团糟。

于 2008-10-30T22:32:20.750 回答
5

我还要说工厂模式。与 Eoin 类似的经历。在我的例子中,这个项目有很多工厂,因为有些人认为你可能使用对象 A 来实现本地实现,对象 B 来实现远程实现,并且它是通过工厂抽象出来的(这是一个明智的做法)。

但是“远程”实现从来没有被需要或实现过,甚至在未来也没有被预见到......而且,技能较低的工程师开始在许多其他事情上采用这种模式,就像千篇一律......

于 2008-10-30T21:35:05.310 回答
4

实际上,我最常看到的是没有使用适当的模式。典型场景:我:“嘿,模块A已经有一段代码循环一组对象并对它们执行数据库操作X,你为什么不重用那段代码?” 编码员:“好吧,但我必须对那些对象进行 Y 操作。” 我:“如何使用重构它以使用命令模式来适当地执行 X 或 Y?”

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

于 2008-10-30T21:21:00.223 回答
3

如果各种逻辑都被归为一个庞大的类,那么中介者模式肯定有可能被滥用。

于 2009-07-30T23:08:31.800 回答
3

实际上,我会说当 KISS (保持简单,愚蠢保持简短和简单)解决方案就是所需要的。

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

于 2008-11-22T02:20:20.880 回答
3

全部。

不要误会我的意思,我发现它们是一个很好的基础,如果理解得很好,非常有帮助。掌握设计技能以了解何时以及如何在代码中应用它们需要付出很多努力。实际上,这就是创建干净代码的技能的总体情况。

它不是关于不使用,这正是您在“使用前三思而后行”的问题中所说的。很好地理解你在做什么以及为什么。如果您不这样做,请与可以指导您的人交谈-除了大量阅读之外。当心那些知道所有模式但无法清楚地向您解释其中任何一种模式的人 - 特别是有问题的模式。

于 2009-09-25T04:34:41.183 回答
2

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

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

《设计模式》这本书唯一真正的意义是为我们每天所做的事情命名,这样我们就可以更好地沟通。

我想如果你是一个新手程序员,通读它们会很有帮助,这样当你需要一个时,你就不必自己弄清楚了,它已经在你的工具箱里了,但总的来说——任何其中一个可以由一帮人(任何一个!)计算出来。

如果有任何这些你还不知道,你可能只是从来不需要它。

给模式命名并稍微正式化它们是非常有用的,我一点也不抱怨这本书。如果你没有看到这里几乎所有的模式偶尔需要,你只是没有在编写非常难的代码(或者你重复了很多代码,我认为这是大罪)。

于 2009-09-26T03:50:59.030 回答
2

我看到的最大的一个是单例模式,在这种模式下,对于如何以及何时调用单例的析构函数没有足够的关注和勤奋。

对于这样一个普遍存在的模式,几乎没有任何关于决定一个单例何时必须死亡的正确过程的讨论。

只是我的0.02。

干杯,

于 2008-10-30T22:57:04.490 回答
1

观察者模式在 C# 中毫无用处,因为它有事件。

于 2008-10-30T21:21:10.800 回答
0

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

让设计从一开始就尽可能简单。当您更多地了解您的设计需要如何更改时,请使用适当的模式,而不是之前。

于 2012-03-22T03:17:10.807 回答
0

存储库模式

大多数人在阅读 Eric Evans 的领域驱动设计书后就开始使用这种模式。

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

于 2012-03-22T03:25:18.567 回答
0

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

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

于 2009-09-25T04:17:26.153 回答
0

你不能对这个问题有直接的答案。它主要是主观的,取决于应用程序的要求。

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

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

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

于 2016-08-04T17:01:28.267 回答