【问题标题】:Simple OOP-related question简单的 OOP 相关问题
【发布时间】:2010-05-10 11:45:46
【问题描述】:

这个问题在我脑海中出现了好几次。

让我通过一个例子来解释我的问题。

假设我有两个课程: 1-网格。 2- 单元格。

现在单元格的位置“应该”存储在网格类中,而不是单元格类本身中。假设单元格想通过网格中的方法获取其位置。

它怎么能做到这一点?请记住,单元格是由 Grid 类创建/初始化的。

有什么好的OO方法来解决这个问题?

谢谢

【问题讨论】:

    标签: c++ oop class


    【解决方案1】:

    我认为这不是一个好的设计。如果单元格需要知道它的位置,它应该自己持有它并为网格提供访问它的方法。

    【讨论】:

    • 单元格可能不需要保存位置。网格可以按需提供位置,调用一些具有位置参数的单元格方法。
    • @ m_pGladiator 当然——有无数种可能的解决方案。我更喜欢先做最简单的。
    • 同意如果单元需要知道它的位置,它应该存储它。但我认为这不是真正的问题。真正的问题是细胞根本不需要知道它的位置。
    • @John 我同意,但这就是问题所在。看起来 Cell 是一个可以摆脱的非对象。例如,如果我在为棋盘建模,我不确定我是否会有一个 Square 类,但显然我会有一个或多个 Piece 类。
    • @Neil - Piece 确实是比 Cell 更好的模型 :)
    【解决方案2】:

    我会这样看:

    • “网格”只是“单元”的集合
    • 每个“单元”在“网格”中都有其作为数据成员的位置
    • 每个“Cell”都可能包含一个“Data”对象,该对象包含“Cell”的实际用户内容

    这样,您可以将“单元格”视为网格内的坐标。

    【讨论】:

    • 这正是我的想法。
    【解决方案3】:

    为什么单元格需要知道它在网格中的位置?似乎细胞应该不知道它的位置。 如果您仍然需要这个 - 单元格可以保存指向其封闭网格的指针,并且可以向其询问位置(像这样,在单元格类中:getGrid().getLocation(this))

    【讨论】:

    • 网格如何知道单元格的位置?搜索?这是一个坏主意,并且会导致传递太多引用,这在 C++ 中并不是一个好主意
    • 通常网格是单元格的父级,因此它知道位置。
    • 你可以把问题转过来:为什么网格需要知道其单元格的位置? “所有这些单元构成网格”可能绰绰有余。
    • -1 询问位置在 OOP 中很臭(告诉,不要询问),并且可能表明设计决策不佳。
    【解决方案4】:

    最好的方法是向网格询问特定单元格的位置。

    另一种解决方案是在单元格的构造函数中为单元格提供一个指向网格的指针。当单元格被请求其位置时,它可以从网格函数返回位置。

    【讨论】:

      【解决方案5】:

      如果您想让单元格知道它的位置,那么只需将其放在单元格内即可。将其排除在课堂之外是没有意义的,并不是说单个单元格可以在不同的网格中使用(因为您已经想要获取它的位置并且设置了这样的限制)。

      或者,如果需要知道位置的单元格方法是从网格调用的,那么我只需将位置作为参数传递给该方法。

      在一些非常特殊的情况下,您可能会将对网格的引用存储在单元格中,或者将其作为参数传递给它的方法,但感觉不对,因为引入了太多的耦合。

      【讨论】:

        【解决方案6】:

        这很简单,只要让Cell的构造函数取它的位置,假设这是构造函数:

        public:
            Cell(/*assume this is a generic type*/T value, int i, int j)
            {
            }
        

        你为什么要这样做?首先是因为在您创建了一个单元格之后,它的位置几乎是固定的,除非您将执行诸如“插入”之类的专门操作。我不建议在 Grid 上调用方法,或者在本地保留 Grid 实例。

        【讨论】:

        • 你为什么认为位置是固定的?您可以将单元格拖放到其他地方(甚至在另一个网格上!)
        • 我同意'Ion',我的观点是单元格的位置是固定的,但单元格的内容不是。因此,如果您拖放某些东西,您正在处理的是该单元格的内容,而不是它自己的单元格。至少我是这么看的。
        • @m_pGladiator,这就是为什么我说“除非你会做插入”,当你拖放时,在大多数情况下这将是一个插入,在某些情况下它将是一个添加,或者它正如 M4 所说,可能两者都不是,因此只是价值变化。
        • 是的,没错,但是 Cell 是可变的——你在移动时修改它的内部内容。我正在以一种类似于拖放的方式思考,实际上是在另一个网格中“重新生成”同一个单元格对象,除了它的位置之外,单元格中没有任何值变化。但是单元格不知道它的位置,因为它是由 Grid 自己管理的。
        【解决方案7】:

        对我来说,单元格似乎没有必要知道它在网格中的位置。重要的是,不是单元格从网格中获取其位置,而是网格在需要时将位置提供给单元格!所以 Grid 调用了 Cell 的一个方法,来做这件事。反之亦然。

        最合乎逻辑的是 Grid 包含许多单元格,因此它“拥有”它们(例如,创建单元格、移动它们或其他任何方式)。因此,Cell 不应该对 Grid 有任何了解。

        单元格本身包含一些信息。根据网格中的位置,可能需要刷新此信息或进行其他操作。然后你可以在 Cell 中有一个方法,由 Grid 调用来执行此操作。如果需要,该方法可能会接受位置参数,但单元格本身并不将它们作为成员。

        【讨论】:

          【解决方案8】:

          正如 Neil 所建议的,如果单元需要知道它的位置,它应该存储它。

          话虽如此,我认为细胞不需要知道它的位置。网格负责管理单元格,包括它们的位置、告诉它们在哪里绘制自己等。单元格应该负责单元格包含的内容——例如,数据、格式信息等。

          所以单元格永远不需要知道它在网格中的位置。它可能需要做一些事情,比如自己绘制,但这应该根据网格传入的屏幕坐标来完成。网格应控制绘制哪些单元格以及在何处绘制。细胞应该只做他们被告知和在哪里做的事情。

          【讨论】:

          • 我实际上是按照这个标准设计了我的项目,但我在想如果单元格保持它的位置,那么它应该提供显示其位置的方法。网格会知道每个单元格的位置,因为它由许多单元格构成。因此,如果一个网格是由 cell[5][5] 创建的,那么 cell[0][0] 就会知道它位于网格中的 (row=0, col=0) 中。电网当然也知道这一点。为了改进设计,我将单元格的位置设置为常数,因此在构建单元格时,位置将从一开始就固定。我认为这不是那么糟糕的设计。
          【解决方案9】:

          网格可以使用某些函数搜索自身的单元格,该函数可以通过缓存或单元格到整数的 n 元组的字典/映射来优化。

          【讨论】:

            【解决方案10】:

            我会考虑将位置存储在每个单元格对象中,并且网格对象应该包含一组单元格,即创建的数量。这样我就可以解决我将面临的一些问题。

            【讨论】:

              【解决方案11】:

              如果这是grid 的责任,那么您必须让cell 知道它属于什么grid。将此添加到单元格的构造函数中。

              这里你要考虑的唯一问题是知道位置到底是谁的责任。

              【讨论】:

                【解决方案12】:

                我猜你说的是网格中单元格的位置不是其“Cell-ness”所固有的,可以这么说,你希望拥有独立于 @ 的 Cell 的概念987654324@,因此单元格对象不应包含任何特定于网格的信息。

                我不确定这种区别有多大价值,但如果你想要,有几个选择:

                • Cell 设为基类,并从中派生GridCell。正如其他答案所暗示的那样,GridCell 包含指向包含 Grid 对象或其位置的反向指针。
                • 在运行时使用the Decorator pattern 之类的东西将特定于网格的信息和接口添加到Cell 对象。

                再一次,闻起来好像我们让这件事变得比现在更难了——我不确定拥有一个不属于 GridCell 是否有意义,而且我没有看到让Cell 对象保持其在网格中的位置是有害的。事实上,让Grid 对象维护一个简单的Cell 对象集合更简单,每个对象负责知道它们在Grid 中的位置。

                【讨论】:

                  【解决方案13】:

                  工厂方法设计模式

                  定义一个用于创建对象的接口,但让您的子类决定要实例化哪个类。工厂方法定义了一个用于创建对象的接口,但让子类决定要实例化哪些类。

                  【讨论】:

                    猜你喜欢
                    • 1970-01-01
                    • 1970-01-01
                    • 2013-04-18
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 2011-09-21
                    • 1970-01-01
                    相关资源
                    最近更新 更多