0

以停车场为例。设计一个停车场,在不同类型的停车位管理不同类型的汽车的停放/取消停放。我们可以先定义一个类ParkingLot,其中包含停车位、总楼层、宽度、停车场长度等。然后我们定义类Vehicle,它可以被不同的车辆类型如Car、Motercycle等继承。我们可以甚至定义类 Parking_Slot 类...

我很困惑的是我应该在哪个类中实现诸如 park() 和 unpark() 之类的动作函数。这些函数似乎与我提到的所有三个类有关:ParkingLot、Vehicle、Parking_Slot。

如果有多个相关的类,任何人都可以解释一下我们应该在哪个类中放置一个函数吗?

4

5 回答 5

2

看一下单一职责原则,它通常说您应该为每个类分配一组密切相关的操作。

试着把你的类分成名词和动词(动作),所以你可以说:-

  • 车辆 -> 公园()
  • ParkingSlot -> 接受(车辆)
  • 停车场 -> 管理(车辆),包含(汽车)

ETC

于 2013-07-22T21:44:23.787 回答
1

这实际上取决于您要实现的目标,不,这并不意味着“没关系,只要它有效,我们就可以将它放在任何类中”-通常有更多的方法来设计某些东西即使好的方法和坏的方法都“起作用”,也比把它设计好更糟糕。显然,如果您不在乎解决方案是否好,您可以做任何您喜欢的事情。

例如,如果您正在模拟一个停车场经理,他试图通过决定哪些车辆去哪里来优化交通流量,那么显然您不希望个别车辆做出他们的停车决定,否则这将完全违背您的目的。 '正在努力完成。也许您有一个管理器对象,将车辆对象放在停车场对象中的停车位对象中,或者您可能会简化并让停车场“做出决定”。如果您只想模拟在公共停车场中被动地发生的情况,驾驶员选择他们来到的第一个空闲空间,那么也许您会让汽车对象来做这件事。

与任何其他模型一样,您从现实中抽象出来,并专注于重要元素,因此您需要确定这些元素是哪些,以及您希望它们做什么,并相应地设计您的类。一旦你为你的特定应用找到了最好的模型,那么这些类实际上会自己编写。

于 2013-07-22T22:05:57.407 回答
0

如果我们将 ParkingLot 视为汽车的容器,那么就像通常所做的那样,park() 函数应该在容器中。然而,这种事情真的会根据你的设计如何发展而改变。

于 2013-07-22T21:39:40.843 回答
0

OOP 完全是关于父子层次结构和多态性,因此您可以在派生类中实现相同的功能。

例如,类 ParkingLot.park() 可能意味着搜索任何可用的停车位,而当您需要更精确地定义它时,您可以获得 ParkingLot 的孩子 - ParkingSlots 并选择最适合您需求的停车位(例如残疾人停车位)。

ParkingLot.parkVehicleAnywhere(const Vehicle& vehicle);
Vehicle.park(const ParkingSlot& slot);
ParkingSlot.parkVehicle(const Vehicle& vehicle);

class Motorcycle : public Vehicle;
class Car : public Vehicle;

然后,您还可以使用双重调度来确定特定于两个选定组件之间交互的行为。

最后但并非最不重要的一点是,当你在推导中建立你的层次结构时,试着问自己一个问题(例如)。

停车场车辆还是车辆?

ParkingSlotParkingLot 还是车辆?

摩托车交通工具还是交通工具?

等等。问自己这些问题可以帮助您建立良好的对象层次结构。

于 2013-07-22T22:07:30.140 回答
0

在 C++ 设计中,将每个动作表示为某个类的方法并不是强制性的。

如果动作只修改了一个对象类型,那么您可以使动作成为该对象类的方法。如果多个对象类型 X,Y[,Z..] 被修改,则更倾向于使操作成为自由函数:

foo(X &, Y &[, Z &...]);

即使只T修改了一种对象类型,如果您可以通过已经属于的基本方法实现它,您仍然应该更喜欢使操作成为自由函数T

foo(T &, Y const &);

而不是:

T::foo(Y const &);

这将T避免不必要的膨胀,并有进一步的建议,这foo(t,y)不仅适用于 ift实际上是 a T,而且“免费”,ift是一种可转换为T特别是从T.

于 2013-07-22T23:01:51.037 回答