【问题标题】:How do I break my procedural coding habits? [closed]如何打破我的程序编码习惯? [关闭]
【发布时间】:2009-02-18 03:59:30
【问题描述】:

我最近阅读了一篇关于 OOP 相关 question 的有趣评论,其中一位用户反对创建“Manager”类:

请去掉管理器这个词 说话时的词汇量 关于类名。的名称 类应该描述它的' 目的。经理只是另一个词 垃圾场。任何 功能将适合那里。这个单词 已成为许多极 糟糕的设计

此评论体现了我成为一名优秀的面向对象开发人员的努力。我在一个只有程序编码员的组织里做程序代码已经很长时间了。似乎我们生成的相对较少的 OO 代码背后的主要策略是将问题分解为可容易识别为离散单元的类,然后将剩余/通用位放入“管理器”中类。

我怎样才能打破我的程序习惯(例如 Manager 类)?大多数 OO 文章/书籍等使用的问题示例本质上很容易转换为对象组(例如,Vehicle -> Car),因此无法为分解更复杂的系统提供太多指导。

【问题讨论】:

  • 这对我来说有点主观。我在围栏上。
  • 我要问这个问题,在 Vehicle->Car 示例中,您是否不想要一个 GravityManager 可以一次将重力应用到 Vehicle 上的所有对象而不是单独的每个对象?或者 CollisionManager 做同样的事情?
  • 是的,我不明白一个词是如何导致编写错误的代码的。我的第一语言是 OO,我在当前项目中有一个以经理结尾的课程。这样做是因为,嗯,它是一个“管理”相关子控件的用户控件。
  • @Suroot 这个类可以简单地称为 Gravity。

标签: oop class-design


【解决方案1】:

首先,我不会再表现得像程序代码是错误的那样。它是某些工作的正确工具。 OO 也是某些工作的正确工具。功能性也是如此。每个范式只是计算的不同观点,存在是因为它便于解决某些问题,而不是因为它是唯一正确的编程方式。原则上,这三种范式在数学上是等价的,因此请使用最能映射到问题域的一种。恕我直言,如果使用多范式语言,如果不同的子问题最好由不同的世界观建模,甚至可以在模块中混合范式。

其次,我会阅读设计模式。如果没有一些实际问题的例子,就很难理解 OO,它有利于解决。 Head First Design Patterns 是一本不错的读物,因为它回答了很多 OO 的“为什么”。

【讨论】:

    【解决方案2】:

    要擅长 OO,需要多年的实践和学习良好的 OO 代码,最好有导师。请记住,OO 只是达到目的的一种手段。话虽如此,以下是一些对我有用的一般准则:

    • 优先组合而不是继承。反复阅读GoF book的第一章。
    • 服从Law of Demeter(“告诉,不要问”)
    • 尝试仅使用继承来实现多态性。当您从另一个类扩展一个类时,这样做的想法是您将通过对基类的引用来调用该类的行为所有基类的公共方法应该对子类有意义。
    • 不要沉迷于建模。构建一个工作原型,为您的设计提供参考。
    • 拥抱重构。阅读Fowler's book的前几章。

    【讨论】:

    • 关于第 3 点 - 为了代码重用,继承如何?也就是说,我想重用我父母的所有代码并增加 1 个功能。这种情况不符合您关于通过对基类的引用来调用行为的声明。这很糟糕吗?
    【解决方案3】:

    single responsibility principle 帮助我将对象分解为有意义的可管理类。

    每个对象都应该做一件事,并且做得很好,而不会将其内部工作方式暴露给需要使用它的其他对象。

    【讨论】:

      【解决方案4】:

      “经理”类通常会:

      1. 询问某物的状态
      2. 根据该状态做出决定

      作为一种解毒剂或与之形成对比的是,面向对象的设计会鼓励您设计类 API,在这些 API 中您“告诉不要要求”类本身去做事情(并封装自己的状态):了解更多关于“告诉不要问”参见例如herehere(也许其他人对“告诉不要问”有更好的解释,但这是 Google 为我找到的前两篇文章)。

      我们生成的小 OO 代码的主要策略似乎是将问题分解为易于识别为离散单元的类,然后将剩余/通用位放入“管理器”类中。

      即使在最好的时候,这也可能是真的。 Coplien 在他的Advanced C++:Programming Styles and Idioms一书的结尾谈到了这一点:他说在一个系统中,你倾向于:

      • 自包含对象
      • 还有,作用于其他对象的“事务”

      以飞机为例(我很抱歉再给你一个交通工具的例子;我在解释他):

      • “对象”可能包括副翼、方向舵和推力
      • “经理”或自动驾驶仪将执行各种命令或事务

      例如,“右转”交易包括:

      • flaps.right.up()
      • flaps.left.down()
      • rudder.right()
      • thrust.increase()

      所以我认为你确实有交易,它跨越或使用各种相对被动的“对象”;例如,在应用程序中,“whatever”用户命令最终将由每一层(例如 UI、中间层和 DB 层)的各种对象实现(因此调用)。

      所以我认为在一定程度上你有“剩余部分”是真的;但这只是程度的问题:也许您应该希望尽可能多的代码是独立的、可封装的,以及一切......以及剩下的部分,使用(或依赖)其他一切,应该给予/使用一个尽可能隐藏和尽可能多的API,因此尽可能多地承担责任(实施细节)远离所谓的经理。

      很遗憾,我只在一本书 (Advanced C++) 中读过这个概念,并且无法将您链接到在线内容以获得比我的这个释义更清晰的解释。

      【讨论】:

        【解决方案5】:

        阅读然后练习 OO 原则对我有用。 Head First Object-Oriented Analysis & Design 通过示例帮助您制定面向对象的解决方案,然后为您提供更好的解决方案。

        【讨论】:

        • 我对 Head First 书籍的主要反对意见是它们过于简化了事情。当您处理围绕 DogDoors 和 GuitarSpecs 设计的系统时,分离关注点和遵守 SRP 会容易得多。
        • 现实生活中的代码比 Head First 书籍中的示例复杂得多。我敢打赌,作者的问题是让他们的例子足够清晰,可以看到他们在教什么,但又足够复杂,看起来像一个真实的例子。
        【解决方案6】:

        您可以通过学习design patterns 来学习良好的面向对象设计原则。 Code Complete 2 是一本关于该主题的好书。自然,将良好的编程原则牢牢记住的最佳方法是通过将它们应用到自己的编码项目中来不断地实践它们。

        【讨论】:

        • 同意。如果不了解它要解决的问题,我认为您无法理解 OO,而这基本上意味着理解设计模式。
        • 我同意你的帖子,除了我不认为 Code Complete 2 一定是一本关于“设计模式”的好书。它比 imo 级别低一点,粒度更细一点。可能是 GoF、HeadFirst 设计模式或其他什么。
        • Code Complete 只介绍了大约十几种设计模式,但我认为它是一本总体上比 GoF 或 HFDP 更好的程序设计书籍。
        【解决方案7】:

        我怎样才能打破我的程序习惯(例如 Manager 类)?

        为经理管理的内容创建一个类(例如,如果您有一个 ConnectionManager 类,则为一个 Connection 创建一个类)。将所有内容移到该类中。

        “经理”在 OOP 中这个名字不好的原因是 OOP 的核心思想之一是对象应该管理自己

        不要害怕制作小类。来自程序背景,您可能会认为创建一个类是不值得的,除非它是一千行代码并且是一些您领域的核心概念。想想更小。十行课程是完全有效的。在你认为有意义的地方创建小类(一个日期、一个邮件地址),然后通过组合这些类来逐步提升。

        当您开始将代码库的一小部分划分为类时,剩余的过程代码汤将减少。在那个不断缩小的池中,您将开始看到其他可以是类的东西。继续,直到池为空。

        【讨论】:

          【解决方案8】:

          换一个灯泡需要多少 OOP 程序员?

          没有,灯泡会自己改变。

          ;)

          【讨论】:

            【解决方案9】:

            您可以使用像 Smalltalk 这样的过程支持很差的 OO 语言。消息发送范式将迫使您进入 OO 思维。

            【讨论】:

            • 我的想法完全正确。使用一种您不能退回到程序性思维的语言(如 Java 或 guhk C++)并且具有良好的 OO 模型。 Smalltalk 是一个很好的选择。
            【解决方案10】:

            我认为你应该从一个好的计划开始。 使用类图进行规划将是一个好的开始。

            您应该确定应用程序中所需的实体, 然后定义每个实体的属性和方法。 如果有重复的,你现在可以重新定义你的实体 以某种方式可以进行继承,以避免冗余。 :D。

            【讨论】:

              【解决方案11】:

              我有一个三步过程,这是我自己成功完成的一个。后来我遇到了一位前教师转为程序员(现在非常有经验),他向我解释了为什么这种方法如此有效,这涉及到一些心理学,但它基本上都是关于在你学习时保持控制和信心。这里是:

              1. 了解什么是测试驱动开发 (TDD)。您可以使用过程代码轻松地做到这一点,因此如果您不想这样做,则不需要开始使用对象。第二步就靠这个了。

              2. 获取 Martin Fowler 的《重构:改进现有代码的设计》的副本。它本质上是您可以对现有代码进行的微小更改的目录。但是,如果没有测试,您将无法正确重构。这使您可以做的是弄乱代码,而不必担心一切都会中断。测试和重构消除了你不知道会发生什么的偏执和感觉,这是令人难以置信的解放。你离开基本上是在玩。随着您对此更有信心,开始探索用于测试对象之间交互的模拟。

              3. 现在是大多数人错误地开始的大事件,它是好东西,但它真的应该排在第三位。在这一点上,您应该阅读有关设计模式、代码异味(这对 Google 来说很好)和面向对象设计原则的内容。还要了解用户故事或用例,因为它们在编写新应用程序时为您提供了良好的初始候选类,这是“我从哪里开始?”的一个很好的解决方案。编写应用程序时遇到的问题。

              就是这样!证明善良!告诉我进展如何。

              【讨论】:

                【解决方案12】:

                当我阅读 Eric Evans 的书 "Domain-Driven Design: Tackling Complexity in the Heart of Software" 时,我对理解面向对象设计的灵感产生了灵感。或者"Domain Driven Design Quickly" 迷你书(以免费 PDF 的形式在线提供),如果您便宜或不耐烦。 :)

                只要您有“Manager”类或任何静态单例实例,您就可能正在构建程序设计。

                【讨论】:

                  猜你喜欢
                  • 2017-06-06
                  • 1970-01-01
                  • 2010-11-28
                  • 2012-07-06
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 2014-04-01
                  相关资源
                  最近更新 更多