在编写面向对象的代码时,我是否应该始终遵循设计模式?


37

任何面向对象的程序都有可想像的设计模式吗?我之所以这么问,是因为最近我看到了带有的Door类的实现Lock。这是测试的一部分,回答说代码遵循Null Object模式:

class Lock
{
public:
    virtual void close() = 0;
    virtual void open() = 0;
    virtual bool is_open() const = 0;
    virtual ~Lock() { }
};

class DummyLock
    : public Lock
{
private:
    DummyLock();
    DummyLock(const DummyLock&) = delete;
    DummyLock& operator=(const DummyLock&) = delete;

private:
    void close() { }
    void open() { }
    bool is_open() const { return true; }

public:
    static DummyLock m_instance;
};

class Door
{
public:
    Door() : m_lock(DummyLock::m_instance) { }
    Door(Lock &lock) : m_lock(lock) { }

public:
    Lock& get_lock() const { return m_lock; }

private:
    Lock &m_lock;
};

这使我想到:即使描述很简单(此类正在设计带锁的门类),该代码仍遵循良好的设计模式,因此,如果我编写更复杂的代码,应该始终存在一些设计模式,正在关注吗?



51
您认为您可以完全用成语说话吗?没有?然后,您不应该通过拼凑设计模式来构建程序。
Kilian Foth,2014年

4
在您的示例中,仅出于学术目的添加了Null对象模式,它没有在此代码中引入“好的设计”。
布朗

4
@djechlin:换句话说,使用“两个词”设计模式:)
Michael Shaw

11
问题是太多的人认为设计模式可以代替思想,可以代替经验(这意味着一定程度的反复试验)。您不能拿一本充满设计模式的书,像Tinker Toys一样将它们放在一起,以生成具有非凡大小,复杂度和质量的应用程序。即使是经验丰富的程序员,也常常需要尝试两到三种设计才能找到可行的设计。
Daniel R Hicks

Answers:


143

我应该始终遵循某些设计模式吗?

亲爱的上帝,不!

我的意思是,您可以继续说任何随机代码都遵循某种随机XYZ模式,但这仅比我自称是我的电脑椅子之王有用。没有人真正知道这意味着什么,即使那些确实不会完全尊重我的主张。

设计模式是一种交流工具,程序员可以在不花费大量时间重复自己的情况下,告诉其他程序员已完成的工作或应完成的工作。而且,由于它们是很多次出现的东西,因此它们是程序员学习的有用概念,“嘿,使XYZ总是看起来很好,因为它很好/有用”。

它们并不能代替您自己思考,为自己面前的独特问题定制模式或处理所有无法放入合适的存储桶中的事情。


5
您的第一段是我将如何回答的一部分。重复出现某东西。如果重复次数足够多,需要进行通信,则它是一种模式,并且可以从名称中受益。甚至有人认为,仅由于缺少某种抽象才能发展出一种模式。追求模式是臭名昭著的货运崇拜成员的耻辱之路。
Magus 2014年

11
@Cerad:当然,只要您保证不写神课!
yatima2975

9
约翰·杜(John Doe)-技术工程师,通用代码猴子和他的电脑椅子之王
2014年

1
可以说,设计应在适当的地方使用模式,而类应这样命名。它们是重要的工具。害怕the_cult(tm)同样危险。
2014年

25
好答案!我的一个批评是“亲爱的上帝,不!” 还不够大
tobyink 2014年

37

没有。

这就是“四人帮”(最初流行设计模式)在他们的书中所说的:

“关于使用设计模式的讨论,如果不多讲一些不使用设计模式的话,是完整的。设计模式不应随意应用。它们通常通过引入附加的间接级别来实现灵活性和可变性,这会使设计复杂化和/或使您付出一些性能。只有在实际需要它提供的灵活性时,才应应用设计模式。”

您显示的示例实际上并没有执行任何操作(我不认为这是故意的,我认为这只是作为一个例子)。就其本身而言,它不需要空对象模式。在更大的程序中,可能会。

错误的方法是假设仅仅因为它被标记为“设计模式”就一定是好的,然后寻找更多的位置填充更多的模式。在适合程序并为您解决问题时使用它们。


7
这本书是《设计模式:可重用的面向对象软件元素》,作者是Erich Gamma,Richard Helm,Ralph Johnson和John Vlissides。
developerwjk

4
+1用于实际引用设计模式的来源。
法拉普2014年

29

如果我要编写更复杂的代码,是否应该始终遵循某些设计模式?

不,设计模式就是:对象之间关系中的模式。换句话说,经常使用和重用的关系足以使人说:“嘿,我们似乎在做很多事情,让我们给它起个名字。” 在OOP开始时并没有一次确定所有的设计模式,而是由GOF传下来!他们被发现并最终被记录下来,然后被书所普及。

就是说,设计模式的最大优势在于,它们使在更高层次上思考软件设计变得更加容易。他们使您无需担心实施细节,而更多地考虑全局。从这种意义上说,它们使您摆脱了细节,但它们也可以以限制您的方式,就像您表示自己的方式可能受到您所知道的单词的限制一样。因此,有可能来的时候,有对于大多数的你做什么,只是因为你知道的模式是在其中您认为条款的设计模式。对于可能滥用模式的情况,以及可能需要更深入地思考做事的更好方法的情况,请睁大眼睛。

同样,要认识到在实践中,您通常没有实现给定的设计模式,而只是在某些现有代码(例如对象框架)中识别出该模式。了解常见的设计模式可以使您更轻松地了解如何使用框架,因为您可以使用已经理解的术语来查看类之间的关系。


10

设计模式有两个优点

  1. 对其他开发人员来说,它们很容易描述,因为人们通常同意这些模式是什么
  2. 他们往往被我们的前辈深思熟虑地殴打,因此他们的长处和短处都广为人知。

每个程序的目标应该是

  1. 有用。它必须执行最终目标,或者使用多少设计模式都无关紧要。OO设计模式使将问题分解为易于理解的部分变得容易,因此更容易证明其可行。
  2. 很容易阅读。这是设计模式很好的地方。他们解决的面向对象问题很复杂。如果您以“标准”方式解决它们,那么下一个开发人员将更容易
  3. 很容易成长。每个人都计划将近0个现代程序完成。每个程序在其初始发行版之后都会增长。OO模式以其擅长增长而闻名。

说了这么多,请注意,每次对OO设计模式的引用都是“他们很擅长工作”。它们并不完美,但是它们确实非常有效地填补了特定市场。在工作时使用它们,在不工作时避免使用它们。

例如,您在问题中提到的“复杂代码”采用我编写的脚本语言。大多数都是面向对象的,到处都是设计模式。但是,当涉及到编写垃圾收集器时,我毫不客气地放弃了所有的OO,因为我需要做的特定事情被更好地建模为良好的老式位扑。在编写终结器之前,整个过程没有OO模式,在这种情况下,OO再次再次成为有用的模型。没有任何浮夸的情况,代码突然又变回了使用OO技术的地步。

只要可以使您的产品更好,就使用设计模式;当它们使您的产品变差时,请避免使用它们。


2
我认为最后一句应该以粗体或摘要开头。
法拉普2014年

5

我会反其道而行之,因为答案比其他答案要微妙得多。您编写的每个类都不应采用设计模式,但是您编写的大多数非平凡程序都应该采用。

没有任何设计模式的简单程序表明:

  • 您的程序是如此独特,以至于它的任何部分都没有程序员以前遇到过的常见问题。要么
  • 您的程序包含这些常见问题,但是您已经以前所未有的更好方式解决了这些问题。

两种情况极不可能发生,没有冒犯。

这并不意味着设计模式应该驱动您的设计,也不意味着您应该不加选择地插入一个设计模式,因为您认为如果不这样做,则看起来会很糟糕。错误的设计模式总比没有糟糕。

它的意思是您应该将整个程序中缺乏设计模式的情况视为一种代码味道。让您重新审视并重新评估您的设计是否更干净的事物。如果此时您决定将设计模式排除在程序之外,那应该是一个有计划的,明智的决定,而不是偶然的事情。

例如,您不必说:“我需要对门和锁进行建模,应该使用哪种设计模式?” 但是,如果您首先设计它而不使用任何设计模式,那之后应该提示您“在此代码中我有大量的空检查,我想知道是否有一种设计模式可以帮助您进行管理”。

看到不同?这是一个微妙但重要的区别。


5
存在比设计模式更多的常见问题(及其常见解决方案)。设计模式是常见的OO解决方案的分类子集,而不是所有常见解决方案的集合。
迈克尔·肖

1
您能否定义“非平凡的”是什么意思,我的印象是“非平凡的”是主观的。
法拉普2014年

1
这是主观的。我的意思是您要在团队中编写的程序,需要持续不断的多个维护人员。
Karl Bielefeldt 2014年

如果您足够幸运,以后再看到您的问题。空检查,确定。安全漏洞?该程序还会在维护过程中中断其他隐患吗?只有下一位工程师才能发现的问题?更令人讨厌。
djechlin 2014年

“我需要对门和锁进行建模,界面应该是什么?性能将成为合同的一部分吗?我应该使用服务或图书馆吗?如何传递资源?” 都应该被问到,并且您应该拥有基本上被视为设计模式的答案。
djechlin 2014年

4

残破的问题。让我给您一个新颖的设计模式定义,它可以消除GoF释放的很多损害:设计模式是一种很好的编码实践。而已。

任何相当复杂的模块都将具有多种设计模式。每当您缓存它时,它可能都是一种轻量级模式,但是如果您不这样称呼,我不会撤销您的编程程度。每当您有回调时,您就处于某种事件/触发/回调模式。等等。如果您有“静态”一词,则您有一个单身人士。如果您有静态构造函数,则有工厂模式。如果将资源传递给模块,则您正在使用依赖项注入。

“设计模式”是GoF流行的一个破烂术语,听起来好像所有的模式都在同一水平上,或者您应该每堂课使用医生建议的3-5。每当您做正确的事而别人做对的事,这就是一种设计模式。例如,A for(;;)是用于表示无限循环的常见模式。

您不应该去尝试学习一堆设计模式。编程知识不会被设计模式索引!相反,您应该学习如何通过阅读书籍,博客和参加您所在领域的会议来编写良好的代码。例如,如果您已经在使用依赖项注入,但是还没有标记它,则始终使用DI或使用IoC框架可能会受益。或者,如果您正在为在事件和回调中正确编写代码而苦苦挣扎,请学习Haskell,以便您熟悉功能设计模式并使其变得容易。

而且,如果您的整个课堂都将别人的所作所为视为一件大事,那么您为什么要重新发明轮子呢?只是用他们的东西。


2
for(;;)惯用什么语言?那可能不是某人“正确”做事的最好例子。
Telastyn

1
@Telastyn C,C ++,Java,Javascript,C#。
djechlin

2
我从来没有见过任何人更希望在while(true)(或while(1)在C,C ++,Java或C#)在我20多年的节目。
Telastyn 2014年

1
@Telastyn stackoverflow.com/a/2611744/1339987开始我开始偏爱while(true),因为它对我来说更具可读性。
djechlin

1
我总是用(;;)。没有特别的原因,我可能在某处阅读过。我喜欢没有任何变量或常量的事实。无论如何,@ Telastyn现在您已经遇到了某人
2014年

0

您应该始终遵循OO设计原则(例如,模块化,信息隐藏,高内聚性等)。设计模式是OO设计原则的相对完善的细分市场,尤其是考虑到KISS原则时

模式是常见设计问题的解决方案。这些问题来自两个地方之一(或两者兼而有之):问题空间(例如,用于管理公司中的人力资源的软件)和解决方案空间。OO程序是解决方案空间中的一个实例(例如,您可以设计OO程序以促进HR管理的多种方式之一)。

知道何时使用模式并不是那么容易。一些模式是低级的,更接近于编码和解空间(例如,Singleton,Null对象,Iterator)。其他问题则由问题空间中的要求所激发(例如,支持撤消/重做的命令模式,支持多种输入/输出文件类型的策略)。

未来需要支持多种软件,因此有许多模式。如果您永远不需要进行这些更改,则模式可能会过度设计。一个示例是使用适配器模式来处理现有的外部HR数据库。您决定应用Adapter,因为当前数据库可与Oracle一起使用,并且您将来可能希望支持NoSQL。如果NoSQL从未出现在您的组织中,那么该适配器代码可能就毫无用处。参见YAGNI。对永远不会发生的变化的支持正在滥用设计模式。


0

模式是常见问题的通用解决方案。我们始终遵循一些模式,GoF的模式处理的是最经常出现的模式。这样可以使软件工程师具有共同的理解和共同的方法。

就是说,我的回答是“否”,但是是的,您始终遵循自己的模式。正如GoF正确指出的那样-

一个人的模式是另一个人的原始构建块。

好报价。


在先前的7个答案中,似乎并没有提供任何实质性的要点和解释
gna

精细。请注意,我提出了一个一般性观点……作为理论讨论,它适用于“设计模式”。
Syed Priom 2014年

“这个网站是所有关于获得答案的地方。这不是一个讨论论坛...”(游览
gna

我确实回答了这个问题。谢谢。对话到此结束。
Syed Priom 2014年

@gnat,虽然简洁得多。
djechlin

0

在编写代码时,我不打算故意使用尽可能多的设计模式。但是,我想,在潜意识里,当我遇到编码问题时,其中一种设计模式似乎很合适,我只是使用它。有时什么都不适合。对我来说,更重要的是编写能完成工作并且易于维护和增长的代码。

这是一篇有关使用设计模式应用OOD原理的文章,并且还提供了代码示例(在C ++中)。它显示了如何以及何时应用某些设计模式来编写简洁的代码。


2
那篇文章是昨天写的。您完全隶属于博客吗?如果是这样,请确实披露该从属关系
Martijn Pieters 2015年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.