什么应该在一个有助于某人开发优秀的OO软件的清单上?

Ada*_*vis 25 c# oop

几年前我使用过OO编程语言和技术(主要是在C++上),但是在这段时间内,OO没有做太多.

我开始在C#中创建一个小实用程序.我可以简单地对它进行编程而不使用良好的OO练习,但对我来说应用OO技术将是一个很好的复习.

就像数据库规范化水平一样,我正在寻找一个清单,它会让我想起一个"好的"面向对象程序的各种经验法则 - 一个简洁的是/否列表,我可以在设计和实现过程中偶尔阅读以防止我从思考和程序上的工作.如果它包含适当的OO术语和概念将更加有用,以便任何检查项目都可以轻松搜索以获取更多信息.

什么应该在一个有助于某人开发优秀的OO软件的清单上?

相反,可以应用什么"测试"来显示软件不是OO?

Daf*_*ees 37

  • 对象的事情.(整个OOP中最重要的一点!)不要将它们视为"数据持有者" - 向他们发送消息来做某事.我班上应该有什么动词?"责任驱动设计"思想学派对此非常出色.(参见对象设计:角色,责任和合作,Rebecca Wirfs-Brock和Alan McKean,Addison-Wesley 2003,ISBN 0201379430.)
  • 对于系统必须做的每件事,提出一系列具体的场景,描述对象如何相互通信以完成工作.这意味着根据交互图进行思考并执行方法调用. - 不要从类图开始 - 这是SQL思维而不是OO思维.
  • 学习测试驱动的开发. 没有人能够预先获得他们的对象模型,但是如果你做了TDD,那么你需要做好基础工作,以确保你的对象模型能够满足它所需要的要求,并在事情发生变化时安全地进行重构.
  • 只针对您现在的要求进行构建 - 不要忽视"重复使用"或"以后有用"的内容.如果你现在只构建你需要的东西,你就可以保留以后可以做的事情的设计空间.
  • 在对对象进行建模时忘记继承.这只是实现通用代码的一种方式.当您对对象建模时,只是假装您通过界面查看每个对象,该界面描述了可以要求它执行的操作.
  • 如果方法需要加载参数,或者如果需要重复调​​用一堆对象来获取大量数据,则该方法可能位于错误的类中.方法的最佳位置就在它在同一个类(或超类......)中使用的大多数字段旁边
  • 阅读适合您语言的设计模式书.如果是C#,请尝试Steve Metsker撰写的"C#中的设计模式".这将教你一系列技巧,你可以用它来划分对象之间的工作.
  • 不要测试对象以查看它是什么类型,然后根据该类型采取行动 - 这是对象可能正在进行工作的代码味道.这是一个提示,你应该调用该对象并要求它完成工作.(如果只有某些类型的对象可以完成这项工作,你可以简单地在某些对象中"无所事事"实现......这是合法的OOP.)
  • 将方法和数据放在正确的类中会使OO代码运行得更快(并为虚拟机提供更好地优化的机会) - 它不仅仅是美学或理论上的.Sharble和Cohen的研究指出了这一点 - 请参阅http://portal.acm.org/citation.cfm?doid=159420.155839(参见"每个方案执行的指令数量"的指标图表)

  • **"计划一切"是失败的最快途径.**你无法做到这一切 - 掌握正确的基础知识并学习如何构建它.这就是重构的目的.另外,请记住Knuth说"过早优化是所有邪恶的根源". (4认同)
  • **如果你学会正确地做到这一点,TDD没有任何问题.**需要学习和练习才能做得好. (3认同)
  • +1。一切都特别好:“不要从类图开始-那是SQL思维而不是OO思维”,“在建模对象时忘记继承”和“仅根据现在的需求进行构建”。 (2认同)
  • TDD可能导致不良的设计,测试您编写的所有内容,但先设计并编写它。 (2认同)
  • 好的清单 - 我同意最重要的是根据对象和他们处理的消息进行思考.一本帮助我极大地使用OOP的书:Arthur Riel的"面向对象设计启发式"http://www.davegardner.me.uk/reading/oo-design-heuristics/ (2认同)

Sea*_*ver 11

听起来你想要一些基本的是/否问题来问自己.每个人都给了一些伟大的"做这个"和"想那样"的列表,所以这里是我的一些简单的是/否的破解.

我可以对所有这些回答是吗?

  • 我的课程代表我所关注的名词吗?
  • 我的类是否提供了它可以执行的动作/动词的方法?

我可以回答所有这些问题吗?

  • 我是否有全局状态数据可以放入单例或存储在与其一起使用的类实现中?
  • 我可以删除类上的任何公共方法并将它们添加到接口或将它们设置为private/protected以更好地封装行为吗?
  • 我应该使用接口将行为与其他接口或实现类分开吗?
  • 我是否有相关类之间重复的代码,我可以移动到基类中以获得更好的代码重用和抽象?
  • 我是在测试某种类型的东西来决定要采取的行动吗?如果可以,这种行为可以包含在有问题的代码使用的基本类型或接口上,以允许更有效地使用抽象,或者是否应该重构有关代码以使用更好的基类或接口?
  • 我是否反复检查一些上下文数据以确定要实例化的类型?如果是这样,可以将其抽象为工厂设计模式,以便更好地抽象逻辑和代码重用?
  • 是一个非常庞大的类,有多个功能的焦点?如果是这样,我可以将它分成多个类,每个类都有自己的单一目的吗?
  • 我是否有从相同基类继承的不相关类?如果是这样,我可以将基类划分为更好的抽象,还是可以使用合成来获取功能?
  • 我的继承层次结构是否变得可怕?如果是这样,我可以通过接口或分割功能将其展平或分离吗?
  • 我对继承层次结构过分担心?
  • 当我将设计解释为橡皮鸭时,我觉得设计愚蠢或者与鸭子说话是愚蠢的吗?

只是一些快速的我的头顶.我希望它有所帮助,OOP会变得非常疯狂.我没有包含任何是/否的更高级的东西,这些东西通常与较大的应用程序有关,例如依赖注入,或者你应该将某些东西拆分成不同的服务/逻辑层/组件....当然我希望你至少将UI与逻辑分开.


RCI*_*CIX 10

从各种书籍,着名的C#程序员和一般建议中收集(如果这些是我的,那就不多了;从某种意义上说,这些是我在开发过程中问自己的各种问题,但就是这样):

  • 结构或类?你正在创建它自己的值的项目,使它成为一个结构.如果它是具有属性和子值,方法和可能状态的"对象",则将其作为对象.
  • 密封类:如果你要创建一个类,并且你没有明确地需要能够继承它,那就让它密封.(我是为了假设的性能增益而做的)
  • 不要重复自己:如果你发现自己复制过去(a/e)代码,你应该(但不总是)重新考虑你的设计,以尽量减少代码重复.
  • 如果您不需要为给定的抽象类提供基本实现,请将其转换为接口.
  • 专业化原则:你拥有的每个对象应该只做一件事.这有助于避免"上帝对象".
  • 使用属性进行公共访问:这一直在争论,但它确实是最好的事情.属性允许您通过字段执行通常无法执行的操作,并且还允许您更好地控制对象的获取和设置方式.
  • 单身人士:另一个有争议的话题,这就是这个想法:只有当你绝对需要时才使用它们.大多数情况下,一堆静态方法可以用于单例的目的.(虽然如果你绝对需要一个单身模式,请使用Jon Skeet的优秀模式)
  • 松耦合:确保你的班级尽可能少地相互依赖; 确保您的图书馆用户可以轻松地将图书馆的部分内容与其他人(或自定义部分)交换出来.这包括在必要时使用接口,封装(其他人已经提到过),以及本答案中的大多数其他原则.
  • 设计时考虑到简单性:与蛋糕结霜不同,现在设计简单的东西比现在设计复杂并稍后删除更容易.

如果我是这样的话,我可能会把一些或所有这些扔出门外:

  • 写个人项目
  • 真的急于完成某件事(但我稍后会再回来......有时.....;))

这些原则有助于指导我的日常编码,并在某些方面大大提高了我的编码质量!希望有所帮助!


ivo*_*ivo 7

史蒂夫麦康奈尔的代码完成2包含许多随时可用的清单,以便进行良好的软件构建.

Robert C. Martin 在C#中的敏捷原则,模式和实践包含了许多优秀OO设计的原则.

两者都将为您提供坚实的基础.

  • 代码完成+1.每章都有一个清单上的项目,我建议查看一下. (2认同)

Mic*_*rdt 7

  • 数据属于在其上运行的代码(即进入同一类).这提高了可维护性,因为许多字段和方法可以是私有的(封装),因此在查看组件之间的交互时在某种程度上不考虑.
  • 使用多态而不是条件 - 每当你必须根据对象是什么类做不同的事情时,尝试将该行为放入一个不同类以不同方式实现的方法中,这样你所要做的就是调用该方法
  • 谨慎使用继承,更喜欢组合 - 继承是OO编程的一个显着特征,通常被视为OOP的"本质".事实上,它严重过度使用,应归类为最不重要的特征


RMo*_*sey 7

  • 我有明确的要求吗?可能没有必要提供正式的需求文档,但在开始编码之前,您应该有一个清晰的愿景.如果您不需要正式文档,思维导图工具和原型或设计草图可能是不错的选择.在软件过程中尽早与最终用户和利益相关者合作,以确保您实现他们所需的.

  • 我重新发明轮子了吗?如果您正在编码以解决常见问题,请寻找已解决此问题的强大库.如果您认为您可能已经解决了代码中其他地方(或者同事可能有)的问题,请首先查看现有解决方案.

  • 我的对象有明确的单一目的吗?遵循封装原则,对象应该具有与其操作的数据一起的行为.一个对象应该只有一个主要责任.

  • 我可以编码到接口吗?Design By Contract是一种很好的方法,可以实现单元测试,记录详细的,类级别的需求,并鼓励代码重用.

  • 我可以对我的代码进行测试吗?测试驱动开发(TDD)并不总是那么容易; 但单元测试对于重构非常有用,并且在进行更改后验证回归行为.与Design By Contract一起携手并进.

  • 我是在过度设计吗?不要尝试编写可重用的组件.不要试图预测未来的要求.这些东西看似违反直觉,但它们会带来更好的设计.第一次编写代码时,只需尽可能直接地实现它,并使其工作.第二次使用相同的逻辑,复制和粘贴.一旦您有两个具有通用逻辑的代码工作部分,您就可以轻松地重构而无需预测未来的需求.

  • 我是否介绍了还原剂代码?不要重复自己(DRY)是重构的最大驱动力.仅使用复制和粘贴作为重构的第一步.不要在不同的地方编写相同的东西,这是一个维护的噩梦.

  • 这是一种常见的设计模式,反模式还是代码味?熟悉OO设计问题的常见解决方案,并在编码时查找它们 - 但不要试图强迫问题适合某种模式.注意代码是否属于常见的"不良实践"模式.

  • 我的代码是否紧密耦合?松散耦合是一种尝试减少两个或更多类之间的相互依赖性的原则.一些依赖是必要的; 但是你越依赖另一个班级,你在班级改变时就必须修复得越多.不要让一个类中的代码依赖于另一个类的实现细节 - 仅根据其契约使用对象.

  • 我暴露了太多信息吗?练习信息隐藏.如果方法或字段不需要公开,请将其设为私有.仅公开对象履行合同所需的最小API.不要使客户端对象可以访问实现细节.

  • 我是防守编码吗?检查错误情况,并快速失败.不要害怕使用异常,让它们传播.如果您的程序达到意外状态,则中止操作,记录堆栈跟踪以供您使用,并避免下游代码中出现不可预测的行为要好得多.遵循清理资源的最佳实践,例如using() {}声明.

  • 我能在六个月内阅读此代码吗?良好的代码是可读的,文档很少.必要时发表评论; 但也要编写直观的代码,并使用有意义的类,方法和变量名.练习良好的编码风格; 如果您正在开展团队项目,团队的每个成员都应该编写看起来相同的代码.

  • 它还能用吗?早期测试,经常测试.引入新功能后,请返回并触摸可能受影响的任何现有行为.让其他团队成员进行同行评审并测试您的代码.在进行更改后重新运行单元测试,并使它们保持最新.


小智 6

其中一个最好的资源是Martin Fowler的"Refactoring"一书,其中包含面向对象代码气味的列表(和支持细节),您可能需要考虑重构.

我还建议罗伯特马丁的"清洁代码"中的清单.


egl*_*ius 5

  • 固体
  • TDD
  • 继承的构成