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

Vic*_*tor 229 architecture oop class-design

我正在开发一个大型项目(对我来说),它将有许多类,需要可扩展,但我不知道如何规划我的程序以及类需要如何交互.

我在几个学期后参加了OOD课程并从中学到了很多东西; 比如编写UML,并将需求文档翻译成对象和类.我们也学习了序列图,但不知怎的,我错过了讲座或其他什么,他们并没有真正坚持我.

在以前的项目中,我尝试过使用从课程中学到的方法,但通常最终得到的代码一旦我能说"是的,看起来像我的想法"我不想挖掘泥土添加新功能.

我有一份史蒂夫麦康奈尔的代码完整副本,我不断听到这里和其他地方都很棒.我阅读了有关设计的章节,似乎没有提供我正在寻找的信息.我知道他说这不是一个削减和干燥的过程,它主要基于启发式,但我似乎无法将他的所有信息都应用到我的项目中.

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

具体来说,我对您使用的方法感兴趣?您遵循的流程是什么,通常会形成一个良好,干净的设计,能够代表最终产品?

Sco*_*ies 194

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

  1. 需求收集.与客户交谈并分析用例以定义软件应具有的功能.

  2. 撰写个人用例的叙述.

  3. 通过叙述并突出显示名词(人,地点,事物),作为候选类和动词(动作),作为方法/行为.

  4. 丢弃重复的名词并分解常用功能.

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

  6. 应用OOD原则来组织您的类(分解常见功能,构建层次结构等)

  • 这确实是一种有用的技术,尤其是当您对问题域没有真正的处理时.然而,它很少产生最佳架构. (6认同)

Dar*_*ryl 66

我还没有足够的声誉发表评论(今天加入)或者我只是评论Scott Davies的回答.加上他不得不说的话:

  1. 在开始之前,请务必确定您的程序是什么.你的课程什么?它不会做什么?它试图解决什么问题?

  2. 您的第一组用例不应该是程序最终将要执行的所有操作的清单.从您可以提出的最小的一组用例开始,这些用例仍然可以捕获您的程序的精髓.例如,对于此网站,核心用例可能是登录,提出问题,回答问题以及查看问题和答案.没有关于声誉,投票或社区维基的信息,只是你所拍摄的原始本质.

  3. 当你提出潜在的课程时,不要只考虑它们所代表的名词,而应考虑它们有什么责任.我发现这是在程序执行期间弄清楚类如何相互关联的最大帮助.很容易想出"狗是动物"或"小狗有一个母亲"之类的关系.通常很难找出描述对象之间运行时交互的关系.你的程序算法至少和你的对象一样重要,如果你已经详细说明了每个班级的工作,它们就更容易设计.

  4. 一旦获得了最小的用例和对象集,就开始编码.获得实际上尽快运行的东西,即使它没有做太多而且可能看起来像垃圾.这是一个起点,并将迫使您回答可能在纸上掩盖的问题.

  5. 现在回过头来选择更多用例,记下它们的工作方式,修改类模型,编写更多代码.就像你的第一次剪裁一样,尽可能少地拍摄,同时还要添加一些有意义的东西.冲洗并重复.

只是我的两分钱.希望它有用.


Ste*_*ini 19

当我有机会时,我通常会使用我称之为"三次迭代规则"的东西.

在第一次迭代(或启动),我设计的应用程序的总体布局根据模型对象,算法,和预期(料,不,也许预期)未来的发展方向.我不编写设计文档,但如果我必须协调多个人,那么当然需要粗略描述该过程,同时分析依赖性和所需时间的猜测.如果像我一样,你更喜欢更敏捷的方法,尽量将这个阶段保持在最低限度.在某些情况下,需要一个强大的设计阶段,特别是当所有事情都已知并且对程序的逻辑真实,并且您计划在代码中的功能之间进行大量交互时.在这种情况下,提供的用例或用户故事是一个很好的高级想法,特别是对于GUI应用程序.对于命令行应用程序,特别是库,请尝试编写"程序故事",在其中编码您必须开发的库并检查它的外观.完成后,这些程序将成为您库的功能测试.

在第一次迭代之后,您将更好地了解事物如何相互作用,了解细节和粗糙点,用一个打耳塞的胶带贴片解决问题.您已准备好利用这些经验来改进,清理,抛光,划分过大的内容,合并过于分散的内容,定义和使用设计模式,分析性能瓶颈和非常重要的安全问题.通常,所有这些更改都会对您编写的单元测试产生巨大影响,但不会对功能测试产生影响.

完成第二次迭代后,您将拥有一颗小宝石,经过良好测试,记录良好且设计精良.现在你有经验和代码来做第三次迭代,扩展.您将添加新功能和用例以改进您的应用程序.你会发现粗糙的斑点,你最终会进入第四次迭代,类似于第二次迭代.冲洗并重复.

这是我对软件设计的一般方法.它类似于螺旋设计,短期,三个月的迭代,以及敏捷开发的元素,使您可以了解问题并了解您的软件及其应用领域.当然,它的可扩展性的问题,因此,如果应用程序是如此之大,涉及数百个开发商,事情比这更复杂一点,但最终我猜的想法是始终不变的,分裂 而治.

所以总结:

  1. 在迭代一中,你会体验它并学习
  2. 在第二次迭代中,您将清理产品并为将来做好准备
  3. 在迭代三中,您可以添加新功能并了解更多信息
  4. 转到2


Dan*_*nas 16

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

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

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

有趣的是,第22如何在线提供课程.


Dav*_*ble 12

它重复但完全正确 - 了解您的数据.

对于OOP,您的课程应该描述重要的信息以及它们如何相互作用.

如果您的心智模型能很好地描述数据的行为和生命周期,那么您可以轻松地安排课程.

这只是一个扩展:确切地知道你要做什么.

  • 对象行为比数据更重要.这是封装的直接结果:面向对象编程的核心.数据暴露(来自C和Pascal等语言)导致系统难以维护(增强和调试),因为您永远不知道系统中的其他位置如何更改数据.OOP与数据无关; OOP是关于行为的.这是一个重要的区别. (12认同)

Eri*_*Red 10

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

http://behaviour-driven.org/


Nom*_*meN 8

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

首先尝试从更高的抽象级别进行思考.考虑主要组件及其职责(它们与其他组件的接口),看一些架构模式的灵感(不,不是设计模式,这些是太低级别!MVC和Multi-Tier是架构模式示例).对于相当大的项目,这样的视图应该有大约3-5个组件.

只有这样你才能放大某个组件并尝试设计它.现在我们处于设计模式和类图的层面.尝试关注项目的这一部分,如果您发现需要将责任添加到其他组件之一,只需将其添加到文档/待办事项列表中即可.不要浪费时间考虑其影响,在这一点上,他们的变化太快,在设计更加稳固时进行审核.

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

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

非常简短:采用面向对象和信息隐藏原则,将其提升到另一个层次!


PS:在设计时做了很多素描,就像真正的建筑一样!

PPS:尝试从不同角度处理问题,在盒子外面思考(尽管盒子可能是要走的路),与同伴讨论对此非常有用......你可以在午餐时谈谈.


Ste*_*ham 7

我在真实项目中使用的技术取得了相当大的成功,是责任驱动设计,灵感来自Wirfs-Brock的书.

从顶级用户故事开始,与同事一起在白板上绘制他们暗示的高级别互动.这让您首先了解大模块是什么; 和一两次高级CRC卡一样,您应该已经稳定了一系列主要组件,它们的作用以及它们如何相互作用.

然后,如果任何职责很大或很复杂,那么通过在模块内部为更高级别交互所识别的每个主要操作播放内部的交互,将这些模块向下细化,直到您拥有足够小且足够简单的对象为止. .

知道何时停止是一个判断问题(只有经验才有).


Sau*_*ron 7

设计模式

创作设计模式

单例 - 确保仅创建一个类的一个实例并为该对象提供全局访问点.

Factory(Factory方法的简化版) - 创建对象而不将实例化逻辑暴露给客户端,并通过公共接口引用新创建的对象.

工厂方法 - 定义用于创建对象的接口,但让子类决定实例化哪个类,并通过公共接口引用新创建的对象.

抽象工厂 - 提供用于创建相关对象族的界面,而无需明确指定其类.

构建器 - 定义用于创建对象的实例,但允许子类决定实例化哪个类,并允许更好地控制构造过程.

原型 - 使用原型实例指定要创建的对象类型,并通过复制此原型来创建新对象.

行为设计模式

责任链 - 它避免将请求的发送者附加到其接收者,这使得其他对象也可以处理请求. - 对象成为链的一部分,请求从一个对象发送到另一个对象,直到其中一个对象将处理它.

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

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

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

介体 - 定义一个封装一组对象如何交互的对象.Mediator通过使对象明确地相互引用来促进松散耦合,并且它允许您独立地改变它们的交互.

Observer - 定义对象之间的一对多依赖关系,以便当一个对象更改状态时,将自动通知和更新其所有依赖关系.

策略 - 定义一系列算法,封装每个算法,并使它们可互换.策略允许算法独立于使用它的客户端.

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

访问者 - 表示要对对象结构的元素执行的操作/访问者允许您定义新操作而不更改其操作的元素的类.

空对象 - 提供一个对象作为缺少给定类型对象的代理./ Null对象模式提供智能无任何行为,隐藏其协作者的详细信息.

结构设计模式

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

Bridge - 将对象组合成树结构以表示部分整体层次结构./ Composite允许客户端统一处理单个对象和对象组合.

Composite - 将对象组合成树结构以表示部分整体层次结构./ Composite允许客户端统一处理单个对象和对象组合.

装饰器 - 动态地向对象添加其他职责.

Flyweight - 使用共享来支持大量具有部分内部状态的对象,其中状态的其他部分可以变化.

Memento - 捕获对象的内部状态而不违反封装,从而提供在需要时将对象恢复到初始状态的方法.

代理 - 为对象提供"占位符"以控制对它的引用.

  • 模式对某些人有用.我认为需要相当多的经验才能看到需求中的模式.你可能需要记录它们.我倾向于认为模式只不过是抽象组件库. (2认同)

Nel*_*nda 5

我会建议你使用BlueJ的,也ActiveWriter学习,也养成了良好的物体上的理解。推荐的书也是不错的参考资料。

维基百科

替代文字

BlueJ是Java编程语言的集成开发环境,主要用于教育目的而开发,但也适合于小型软件开发。

另外,它使用UML,对我来说,这是理解对象建模的好资源。

替代文字http://www.ryanknu.com/ryan/bluej.png

ActiveWriter是建模实体和关系的工具,它还生成代码并且易于更改。这将节省您的时间,对于敏捷开发非常适合。

替代文字
(来源:altinoren.com