你如何设计面向对象的项目?

我正在处理一个大型项目(对我来说),它将有许多类,需要可扩展,但我不确定如何规划我的程序以及类需要如何交互。

几个学期前我上了一门OOD课程,从中学到了很多东西;比如编写UML,并将需求文档转换为对象和类。我们也学过序列图但不知怎么的我错过了这节课,我没能记住它们。

在之前的项目中,我尝试使用从课程中学到的方法,但通常在我说“是的,这看起来像我想要的东西”时,我就会以代码结束,我不想再挖掘出新的功能。

我有一本史蒂夫·麦康奈尔的代码完成,我经常听到它是惊人的,在这里和其他地方。我读了关于设计的章节,似乎没有得到我想要的信息。我知道他说这不是一个固定的过程,它主要是基于启发式,但我似乎不能把他所有的信息都应用到我的项目中。

所以在高级设计阶段(在你开始编程之前),你要做些什么来确定你需要什么类(特别是那些不基于任何“现实世界对象”的类),以及它们如何相互交互 ?

我特别感兴趣的是你使用的方法是什么?你遵循什么样的过程,通常会产生一个良好的,干净的设计,将接近最终产品?

105644 次浏览

它经常被重复,但完全正确——理解你的数据。

对于面向对象编程,你的类应该描述重要的信息片段以及它们如何交互。

如果您有一个心智模型,它很好地描述了数据的行为和生命周期,那么您将很容易布局您的类。

这句话其实是“确切地知道你要做什么”的延伸。

我建议你使用BlueJ和ActiveWriter来学习和发展对对象的良好理解。推荐的书也是很好的资源。

维基百科:

alt text

BlueJ是一个综合开发项目 Java编程环境 语言,主要是为了 教育的目的,也是 适用于小规模软件 发展。< / p >

此外,它使用UML,对我来说,这是一个很好的资源来理解建模对象的一些事情。

alt text http://www.ryanknu.com/ryan/bluej.png

ActiveWriter是一个建模实体和关系的工具,它也可以生成代码,并且很容易进行更改。它将节省您的时间,并且对于敏捷开发非常适合。

< p > alt text < br > (来源:altinoren.com) < /订阅>

老实说,最好是回头看看流程图和序列图。有大量的好网站告诉你如何做到这一点。当我考虑如何将程序分解为类时,我发现这是非常宝贵的,因为我确切地知道程序需要输入、计算和输出什么,并且每一步都可以分解为程序的一个部分。

当我有机会时,我通常会使用我所谓的“三次迭代规则”。

在第一次迭代(或启动)中,我根据模型对象、算法和预期的(真的预期,而不是也许预期)未来方向设计了应用程序的总体布局。我不编写设计文档,但如果我必须协调多个人员,那么当然需要一个程序的粗略草图,以及对依赖关系的分析和所需时间的估计。如果您像我一样喜欢更敏捷的方法,请尽量减少这个阶段。有些情况下,需要一个强大的设计阶段,特别是当你的程序逻辑的一切都是已知和真实的,如果你计划在你的代码中的功能之间进行大量的交互。在这种情况下,用例或用户描述是一个很好的高级想法,特别是对于GUI应用程序。对于命令行应用程序,特别是库,试着编写“程序故事”,在这些故事中,您必须根据必须开发和检查的库编写代码。这些程序完成后将成为库的功能测试。

在第一次迭代之后,你会更好地理解事物是如何相互作用的,找出细节和粗糙的地方,用胶带补丁解决问题。您已经准备好利用这些经验来改进、清理、优化、划分过大的部分、合并过于分散的部分、定义和使用设计模式、分析性能瓶颈和重要的安全问题。一般来说,所有这些更改将对您编写的单元测试产生巨大影响,但不会对功能测试产生影响。

当您完成第二次迭代时,您将拥有一个经过良好测试、良好记录和良好设计的小珍宝。现在您已经有了进行第三次迭代(扩展)的经验和代码。您将添加新的特性和用例来改进应用程序。你会发现一些粗糙的地方,最终你会进入与第二次类似的第四次迭代。清洗并重复。

这是我软件设计的一般方法。它类似于螺旋设计,具有简短的,三个月的迭代,以及敏捷开发的元素,允许您了解问题并了解您的软件及其应用领域。当然,这是一个可伸缩性的问题,所以如果应用程序如此之大,以至于涉及数百个开发人员,事情就会比这复杂一些,但最终我想想法总是一样的, 治之

总结一下:

  1. 在第一次迭代中,您将体验并学习它
  2. 在迭代2中,您将清理产品并为未来做好准备
  3. 在迭代3中,您添加了新特性并了解了更多
  4. 转到2

我用于初始设计(得到类图)的步骤是:

  1. 需求收集。与客户交谈并提出用例来定义软件应该具有的功能。

  2. 编写单个用例的叙述。

  3. 遍历叙述并突出名词(人、地点、事物),作为候选类和动词(动作),作为方法/行为。

  4. 丢弃重复的名词,剔除常见的功能。

  5. 创建类图。如果你是一个Java开发人员,来自Sun的NetBeans 6.7有一个UML模块,它允许绘图和往返工程,而且是免费的。Eclipse(一种开源Java IDE)也有一个建模框架,但我没有使用它的经验。您可能还想尝试ArgoUML,这是一种开源工具。

  6. 应用OOD原则来组织你的类(提取公共功能,构建层次结构,等等)

尝试使用行为驱动开发。要打破你的旧习惯很难,但我发现BDD确实是你在现实世界中开发的最佳选择。

http://behaviour-driven.org/

一个有用的技巧是将你独特的问题描述与你在现实世界中可以找到的东西联系起来。例如,你正在为一个将席卷全球的复杂医疗保健系统建模。有什么例子你可以随时调用建模吗?

确实。观察旁边的药房是如何运作的,或者医生的房间。

把你的领域问题归结为你能理解的问题;一些你能联想到的东西。

然后,一旦领域内的“玩家”开始出现,并且你开始对代码建模,选择“提供者-消费者”建模方法,即你的代码是模型的“提供者”,是“消费者”。

与领域相关并在较高层次上理解它是任何设计的关键部分。

我认为这里的答案应该是非常不同的,这取决于这个人的真实世界经验。

如果你只有一到两年的工作经验,那么你必须去的点是:如何你得到的点,你真的知道你的数据,并确切地了解你正在尝试做什么?

是的,如果您已经在现实世界中工作了5年以上,那么您可以在许多软件开发过程模型或技术中选择任何一种。

但是光靠读书是得不到经验的。你应该在一个好的领导下的好团队中学习。

如果这是不可能的,那么你应该自己做。从编写一段可能非常糟糕的代码开始迭代,学习错误,丢弃所有错误,编写更好的代码等等。

您将学到很多关于代码库的知识。工具就是工具,它们不会教你任何东西。

你问了一个很多作家用来写书的问题。有很多方法,你应该选择一个对你来说“最漂亮”的。< br > 我可以推荐Eric Evans的书领域驱动设计。另外,检查site dddcommunity.org.

.

.

.
  1. 研究,掌握设计模式。
  2. 接下来,学习领域驱动设计
  3. 之后,学习需求收集
我上了几个学期的OOD课程 回来后,我学到了很多;就像 编写UML和翻译 将需求文档转换为对象 和类。我们学过序列 图表也有,但不知怎么的,我错过了 讲座之类的,他们没有

  1. 你知道第三步。你需要掌握它。我的意思是,通过大量的练习让它成为你的第二天性。这是因为你学习的方法,与我们过去的方式截然相反。所以你需要真正掌握它。否则,你会发现自己总是回到原来的做事方式。这有点像测试驱动流程,很多java开发人员在尝试了几次后就放弃了。除非他们完全掌握它,否则这对他们来说只是一种负担

  2. 编写用例,特别是备用课程。备用课程占据了我们开发时间的50%以上。通常,当你的经理给你分配一项任务时,比如创建一个登录系统,他会认为这很简单,你可以用1天的时间来完成它。但是他从来没有考虑到,你需要考虑,1。如果用户输入错误的密码怎么办?如果用户输入错误的密码3次,3。如果用户没有输入用户名怎么办?你需要列出它们,并将其展示给你的PM,请他重新安排最后期限。

大型项目的问题在于您无法监督组件之间的所有交互。因此,降低项目的复杂性是很重要的。类图和序列图对于这个设计阶段来说太详细了。

首先试着从更高的抽象层次来思考。考虑主要组件及其职责(它们与其他组件的接口),查看一些架构模式以获得灵感(不,不是设计模式,这些太低级了!MVC和多层是架构模式的例子)。 对于相当大的项目,这样的视图应该有大约3-5个组件

只有这样,你才能放大到某个组件,并尝试设计它。现在我们到了设计模式和类图的层次。试着把注意力集中在项目的这一部分,如果你发现你需要向其他组件之一添加一个职责,就把它添加到你的文档/待办事项列表中。不要在这个时候浪费时间思考它们的含义,因为它们的变化太快了,当设计更加可靠时再进行检查。

此时您不需要完整地设计每个组件,尽管使用一段代码来实现未实现的组件接口并生成简单但有用的响应可能是明智的。这样,您就可以一次开始开发(和设计)一个组件,并对其进行合理的测试。

当然,当新组件完成后,您应该在继续之前测试它们如何(以及是否)相互集成。

总之: 采用面向对象和信息隐藏原理,并将其提升到另一个层次!< / p >
< p > PS: 在设计的时候画很多草图,就像真正的建筑一样!< / p > < / p >

PPS:试着从不同的角度来看待这个问题,跳出固有的思维模式(尽管固有的思维模式可能是正确的),与同行讨论可能会非常有用……午餐时你们有话可聊。

关于这一点,我所知道的最有趣的来源是Bertrand Meyer的面向对象的软件构建,第2版的D部分。

第四部分:面向对象的方法论:很好地应用该方法

19:在方法论上, 20:设计 模式:多面板交互 系统中, 21:传承案例研究: 在交互系统中,22: 如何找到课程 23: 课程设计原则,24:使用 继承好,25:有用 技巧,26分:风格感,27分: 面向对象分析,28:The 软件构建过程,29: 教学方法

有趣的是,22。如何找到类这一章可以在网上找到。

我在实际项目中使用的成功的技术是责任驱动设计,灵感来自Wirfs-Brock的书。

从最顶层的用户故事开始,与同事一起,在白板上勾勒出它们所暗示的高级交互。这让你对大模块有了初步的了解;重复一两次高级CRC-card(游戏邦注:如play),你应该已经稳定了一个主要组件列表,它们的作用以及它们如何相互作用。

然后,如果任何职责很大或很复杂,那么细化这些模块,直到有足够小且简单的东西成为对象,方法是在模块内执行由更高级别交互确定的每个主要操作的交互。

知道什么时候该停下来是一个判断问题(只有经验才能决定)。

恐怕这不是一个答案人们喜欢听。无论如何,让我陈述我的观点。

OOP应该被视为一种范式,而不是一种高级范式。面向对象编程适合于解决某些问题,比如开发一个GUI库。它也符合大型软件公司通常遵循的软件开发风格——设计师架构师的精英团队在UML图或其他类似的介质中制定软件设计,而开发人员的不太开明的团队将设计转换为源代码。如果您独自工作或与一个由极有才华的程序员组成的小团队一起工作,OOP提供的好处很少。然后,最好使用一种支持多种范式的语言,这将帮助你快速想出一个原型。Python、Ruby、Lisp/Scheme等都是不错的选择。原型就是你的设计。然后再改进。使用最能解决手头问题的范例。如果需要,可以使用C或其他系统语言编写的扩展来优化热点。通过使用这些语言中的一种,你还可以免费获得可扩展性,不仅在程序员级别,而且在用户级别。像Lisp这样的语言可以动态地生成和执行代码,这意味着您的用户可以用软件本身编码的语言编写小的代码片段来扩展应用程序!或者,如果选择用C或c++编写程序,可以考虑为Lua这样的小语言嵌入一个解释器。将函数公开为用该语言编写的插件

我认为,大多数时候OOP和OOD所创造的软件都是过度设计的受害者。

总之,我喜欢的写软件的方式是:

  1. 使用动态语言。
  2. 用这种语言编写设计(原型)。
  3. 如果有必要,使用C/ c++优化某些领域。
  4. 通过实现语言本身的解释器提供可扩展性。

最后一个特性使软件能够轻松地适应特定用户(包括我自己!)的需求。

设计模式

创造性设计模式

单例——确保只创建类的一个实例,并提供对象的全局访问点。

Factory(Factory Method的简化版)—创建对象时不向客户端公开实例化逻辑,并通过公共接口引用新创建的对象。

Factory方法——定义一个用于创建对象的接口,但是让子类来决定实例化哪个类,并通过公共接口引用新创建的对象。

抽象工厂——提供了创建一系列相关对象的接口,而无需显式地指定它们的类。

Builder -定义一个创建对象的实例,但让子类决定实例化哪个类,并允许对构造过程进行更精细的控制。

Prototype—指定使用原型实例创建的对象类型,并通过复制该原型创建新对象。

行为设计模式

责任链-它避免了将请求的发送方附加到其接收方,从而使其他对象也有可能处理请求。 -对象成为链的一部分,请求通过链从一个对象发送到另一个对象,直到其中一个对象处理它

命令-将请求封装在对象中,允许对不同请求的客户端进行参数化,并允许将请求保存在队列中。

解释器——给定一种语言,为其语法定义一个表示法,并定义一个解释器,使用该表示法解释该语言中的句子/将域映射到语言,将语言映射到语法,将语法映射到分层面向对象的设计

迭代器——提供一种方法,可以按顺序访问聚合对象的元素,而不暴露其底层表示。

中介——定义一个对象,它封装一组对象如何交互。Mediator通过防止对象显式地相互引用来促进松耦合,并且允许您独立地改变它们的交互。

观察者——在对象之间定义一对多的依赖关系,这样当一个对象改变状态时,它的所有依赖关系都会被自动通知和更新。

策略——定义一组算法,封装每个算法,并使它们可互换。策略允许算法独立于使用它的客户机而变化。

模板方法——在一个操作中定义一个算法的框架,将一些步骤推迟到子类/模板方法让子类重新定义算法的某些步骤,而不让它们改变算法的结构。

Visitor -表示要在对象结构的元素上执行的操作/ Visitor允许您定义一个新操作,而无需更改其操作的元素的类。

空对象——提供一个对象作为缺少给定类型对象的代理。/空对象模式提供了智能的无为行为,对合作者隐藏了细节。

结构设计模式

适配器——将一个类的接口转换成客户端期望的另一个接口。/ Adapter允许类一起工作,否则由于不兼容的接口而无法一起工作。

桥接——将对象组合成树形结构来表示部分-整体层次结构。/ Composite允许客户端统一地处理单个对象和对象的组合。

复合——将对象组合成树状结构来表示部分-整体层次结构。/ Composite允许客户端统一地处理单个对象和对象的组合。

装饰器——动态地向对象添加额外的职责。

Flyweight——使用共享来支持大量的对象,这些对象的部分内部状态是相同的,而另一部分状态可能是不同的。

记忆碎片——在不违反封装的情况下捕获对象的内部状态,从而提供了在需要时将对象恢复到初始状态的方法。

代理——为对象提供一个“占位符”来控制对它的引用。

首先,设计应该来自你的灵魂。你必须用每一根纤维去感受它。在我开始做任何事情之前,我通常会走两三个月,只是在街上走(真的)。和思考。你知道,散步是一种很好的冥想。所以它能让你更好地集中注意力。

其次,只在存在自然对象层次结构的地方使用OOP和类。不要人为地把它“拧”进去。如果没有严格的层次结构存在(就像在大多数业务应用程序中一样)-选择过程式/函数式,或者至少只将对象用作具有隔离访问器的数据容器。

最后——试着读这个:创造性思维的算法

斯科特·戴维斯补充说:

  1. 在开始之前一定要确保你知道你的程序是关于什么的。什么 你的程序?会怎样?它要解决什么问题?

  2. 您的第一组用例不应该是程序最终要做的所有事情的洗衣清单。从你能想出的最小的用例集开始,它仍然抓住了你的程序的本质。例如,对于这个网站,核心用例可能是log inask a questionanswer a question,和查看问题和答案。与声誉、投票或社区wiki无关,只是你所追求的原始本质。

  3. 当您想到潜在的类时,不要仅仅从它们代表什么名词的角度来考虑它们,而是要考虑它们具有什么职责。我发现这是在程序执行期间找出类之间关系的最大帮助。我们很容易想到“狗是一种动物”或“小狗有一个妈妈”这样的关系。通常很难找出描述对象之间运行时交互的关系。你的程序的算法至少和你的对象一样重要,如果你清楚地说明了每个类的工作是什么,它们就更容易设计。

  4. 一旦你得到了用例和对象的最小集合,开始编码。尽可能快地获得一些实际运行的东西,即使它没有太多功能,可能看起来像垃圾。这是一个起点,它会迫使你回答那些你在纸上可能会忽略的问题。

  5. 现在回过头来选择更多的用例,写出它们如何工作,修改类模型,并编写更多的代码。就像你第一次剪头发一样,每次剪得越少越好,同时还要添加一些有意义的东西。清洗并重复。

这只是我的个人意见。希望对大家有用。

在设计类结构的过程中,我注意到从编写一些伪代码开始是非常有用的。这意味着:我从在最高级别上“编写”应用程序代码的一些一般片段开始,摆弄它,并发现正在出现的元素——实际上,作为程序员的我想要使用的元素。对于设计模块的一般结构及其交互来说,这是一个非常好的起点。经过几次迭代,整个结构开始看起来更像一个完整的类系统。这是设计部分代码的一种非常灵活的方式。你可以称之为面向程序员的设计。

如果你对你要从事的项目有专业知识,比如银行业。你可以很容易地构建你的对象,而且你知道每隔一天就会有这些增强。

如果你没有这方面的专业知识,那就和有这方面专业知识的人合作,把这些想法转化为技术细节。

如果你对如何组织你的项目设计感到困惑。盲目地遵循“实用的程序员”这本书。我以前也遇到过同样的情况,试着读那本书的一章。它会改变你作为软件开发人员的思维方式。

学习设计模式。在过去的两年里,这是我个人在面向对象编程方面的革命。找一本书。我向你推荐这个:

头部优先设计模式

它使用Java,但可以扩展到任何语言。

只是引用http://www.fysh.org/~katie/computing/methodologies.txt

RUP的核心是一个你必须使用面向对象设计的小区域 人才……如果你没有它们,就像有一个方法论

"第一步:写关于跑得非常快的事情。 第二步:画一张赛马场平面图。 第三步:去买紧身的莱卡短裤。 第四步:跑得非常、非常、非常快。 第五步:先交叉线"

第四步才是最难的一步。但如果你特别强调 在第1 2 3 5次,有可能没有人会注意到,然后你就可以 卖这个方法可能会赚很多钱 那些认为成为百米运动员有什么“秘密”的运动员

我使用测试驱动设计(TDD)。首先编写测试实际上有助于引导您获得干净和正确的设计。看到http://en.wikipedia.org/wiki/Test-driven_development