何时需要召集四人帮?[何时使用设计模式?]

14

《面试游击指南》中,Joel说那些想要完成事情但不够聪明的人会做一些愚蠢的事情,比如使用访问者设计模式,而使用简单数组就足够了。

我发现很难判断是否应该使用GoF建议的设计模式。

因此,我想要从您的工作经验中得到一些例子:

  • 何时使用简单方法(固定大小的数组)即可?
  • 什么样的软件最小程度上能证明使用GoF设计模式是合理的?
  • 何时将代码从简单的思路重构成GoF模式?是否可以进行有意义的重构?
7个回答

19

我经常发现使用测试驱动开发有助于在面对这些问题时指导我。

  • 什么时候使用简单的方法就足够了? 总是使用最简单的方法来通过下一个测试是足够的。但是,知道何时/如何重构才是真正的艺术形式。
  • 什么样的软件大小才能证明使用GoF模式的必要性? 我曾经读过的一个经验法则是:当你编写某些代码时,可以。当你在另一个地方复制该代码时,请记下并继续进行。当您第三次发现需要相同的代码时,就是时候重构以消除重复并简化,通常涉及移动到设计模式。
  • 何时从简单思维重构到GoF? 我喜欢@anopres所说的 - 当你感到没有设计模式时的痛苦时,就是时候了。痛苦(或代码“气味”)可能会以多种方式表现。代码重复是最明显的。像Fowler的Refactoring或Kerievsky的Refactoring to Patterns这样的重构书籍列出了许多这样的痛点/代码臭味。
  • 这种[重构]能以明智的方式完成吗? 重构的诀窍是拥有一套您信任的单元测试,并进行重构,而不会导致这些测试中任何一个失败。重构根据定义不会改变代码的功能。因此,如果您的测试继续通过,您就可以非常有信心地知道您没有破坏任何东西。虽然这可能很困难,但我实际上喜欢TDD的这个部分,这几乎像是一个游戏,使更改而不破坏任何测试。
总之,我认为TDD有助于指导我编写足够的代码,并且更重要的是,在需求不可避免地发生变化、需要更多功能等情况下,帮助我稍后进行更改。

12

设计模式是结果,而非目标。你不会想着“今天我要使用策略模式”,而是自然而然地使用它。当你在做第三个几乎相同的类时,你停下来拿起笔记本,思考通用情况并编写一个描述共享上下文的基类。然后将前两个类重构为子类,并对基类进行现实检查和修改。然后接下来的三十个类就变得轻松自如了。

直到第二天的团队会议上,你说:“我使用了策略模式。它们都工作得很好,所以只有一个测试程序,需要改变测试用例的参数。”这样你就为大家节省了30分钟的无聊时间。

熟悉设计模式可以使你在需要的情况下自然而然地使用它们。但如果人们将使用模式视为自己的目标,则会产生僵化、丑陋的代码,更多地关注机制而非目的;更关注如何做而非为什么这样做。


大多数模式解决的是诸如复杂性缓解和提供可扩展性点等经常出现的基本问题。如果明确不需要提供可扩展性点,那么提供它们只会无谓地增加代码的复杂度,并创建更多的故障点和测试用例。除非你正在构建一个发布到野外的框架,否则只解决实际面临的问题。


策略模式的简单解释! - Nathan

11

模式只是工具和词汇。您编写代码时应尽可能简单、易于理解和可维护。通过了解模式,您可以拥有更多选择,还可以在实施之前讨论方法的利弊。

无论哪种情况,您都不只是“切换”到“使用模式”。您只需按照自己最熟悉的方式编写最佳代码即可。


7
这与其他任何设计决策类似,最终取决于情况。您应该学习那些在您的语言中有用的模式(例如,Lisp或Smalltalk并不需要许多GoF模式),了解它们的优缺点,理解您的系统的限制,并选择最适合您需求的方案。
我能给出的最好建议是不断学习。

很少有发布的产品是用Lisp或Smalltalk构建的,我认为这可能是因为虽然C是低级别的,但可以通过谨慎使用模式来实现高级别的设计。因此,您的工具可以根据情况要求高或低级别。这背后的问题是对开发人员理解和技能的要求。是的,我已经思考了你的答案七年了。 :) - Peter Wone
我认为没有多少产品使用Lisp或Smalltalk,因为当微型计算机革命发生时,程序员的数量激增,早期微型计算机只能使用低级语言。因此,即使在微型计算机可以做更多事情之后,新的程序员也都习惯于使用低级语言。直到30年后,微型计算机编程文化才几乎赶上了Lisp和Smalltalk,出现了像Perl、Python、Ruby和JavaScript这样的语言。公正地说,我写的生产代码中,用C的比用Lisp和Smalltalk的总和还要多。 - Andru Luvisi
此外,C语言设计非常精妙。在数据结构中使用函数指针可以提供大量面向对象编程的功能。我相信Unix设备驱动程序系统是面向对象编程的早期示例,其中主设备号选择驱动程序(一组过程),次设备号选择设备(特定状态的集合)。驱动程序是类,设备是对象。这是通过在结构中存储函数指针来实现的。能够引起您思考的荣幸之至! - Andru Luvisi

3
从简单方法转向正式设计模式通常是随着问题复杂度的增加而自然发生的。关键在于要熟悉这些模式,以便在问题达到临界点时能够识别并从简单方法切换到设计模式,从而为当前和未来的开发带来最大的收益。
对于更大、更复杂的项目,应该尽早达到临界点;在许多情况下,甚至在编码之前就可以实现模式。对于较小的项目,您可以等待一段时间再决定是否实施模式。
为了增强您识别何时应使用模式的能力,最好的方法之一是在完成项目后花一些时间检查您的“简单”方法变得多么复杂。如果实施模式需要更少的时间和精力,或者模式可以澄清您试图做什么,那么您可以将这些知识存档,以备下次遇到类似的问题时使用。

2

当你遇到一个可以用设计模式解决的问题时,GoF书籍的每一章都有一节介绍每个模式适用于哪些场景。你不应该分析每个问题然后去查找要使用哪种模式。相反,你应该熟悉这些模式,以便学会识别何时需要使用它们。


0

关于GoF的原始书籍之一最好的地方之一是讨论模式在哪些情况下最好解决问题。回顾这些讨论可以帮助您确定“是时候了”。

另一个好的起点是《Head First设计模式》。演示不同设计模式使用的练习足够详细,可以提供很好的学习体验。此外,这些练习也基于现实世界的场景,因此应用设计模式的适当时间从未是一种牵强附会。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接