类的类设计几乎没有什么不同
Class Design for Classes with few differences
考虑一个名为Vehicle的抽象类。该车辆具有以下抽象操作
- - - - - -开始- - - - - -休息——加快
class Vehicle
{
public:
virtual void Start() = 0;
virtual void Break() = 0;
virtual void Accelerate() = 0;
};
现在考虑从vehicle类派生出一种特殊类型的车辆,即vehicle - lea。
Class VehicleA: public Vehicle
{
private:
double speed;
double temperature;
int id;
double miles;
public:
void Start();
void Break();
void Accelerate();
void horn();
};
如果我现在有一辆几乎与vehicle - lea类型相似的车辆,但在引擎类型或其他一些特征(如颜色)上略有不同,这是适应类层次设计中如此小的变化的最佳方式。我应该
定义从Vehicle类派生的另一个类VehicleB ?或者
定义另一个类VehicleB派生自VehicleA ?或者
谢谢
根据类Vehicle
对你的实际意义(注意,在进行这种类设计时,直觉不一定是你最好的朋友:想想著名的Square/Rectangle案例),你可以用以下方式声明你的vehicle - lea(不要忘记虚拟关键字):
class VehicleA: public Vehicle
{
private:
//Your specific private
Engine* m_engine;
Color* m_color;
//Add any "modifiable" part as long as it fits
public:
virtual void Start();
virtual void Break();
virtual void Accelerate();
void horn();
};
与Engine
和Color
两个类(可以是抽象的或非抽象的),包含您想要实现的细节。
你添加了另一个抽象层次:你的VehicleA
有一个引擎(有自己的接口),但不关心它的细节(只要引擎有一个车辆可以交互的接口),并且可以很容易地添加一个新的类型的引擎。
作为设计层次结构时的一般规则,如果您认为必须实现特定类的新派生类,请问自己以下问题:
这个类是它父类的一个更具体的版本吗?
在你的情况下,感觉一个VehicleB不会是一个更具体的版本的VehicleA,尽管这仍然是一个意见问题,因为它完全取决于你想做什么。在这种情况下,感觉应该采取的方法是组合。
您这里遇到的是一个与"关注点分离"相关的问题。"车辆"概念有一些基本操作,其中一些您可以识别,例如"加速"。现在"加速"的实现依赖于某些参数,如最大扭矩,制动马力等…
这些应该封装在车外…但是为什么呢?因为运载工具代表的是一个概念,而不是一个实现。加速将以同样的方式使用引擎,无论涉及哪种类型的汽车。让我举一个现实世界的例子:迈凯轮F1是一辆车,实际上它是一辆车,它包含一个引擎,一个底盘,一些轮胎和悬架等等……大众高尔夫GTI是一辆汽车,实际上它是一辆汽车,它包含一个发动机,一个底盘,一些轮胎和悬挂等…
用户将以完全相同的方式驾驶一辆车和另一辆车,即使它有非常不同的组件组。用户甚至不需要知道大部分的细节。这就是为什么您需要将您的Vehicle概念与由您的Vehicle的特定组件封装的实现细节分开。你也应该为你的"刹车"做同样的事情,你应该在构建时将引擎和刹车注入到车辆中(查找依赖注入)。
现在是颜色:我建议你把它放在类层次结构的顶层,在Vehicle抽象类中。它适用于所有类型的车辆,并且被所有车辆以相同的方式使用,并且不影响任何实现。它应该通过构造函数设置,并提供repaint
函数来更改它(当然,一旦必要的费用通过SalesPoint传递给Garage !)。
所以最后的类可能看起来像这样…
class Vehicle
{
private:
std::unique_ptr<Engine> engine;
std::unique_ptr<Brake> brakes; // same for "Suspension", "Chassis" etc...
VehicleColour colour; // An enum defined here or elsewhere.
public:
Vehicle( std::unique_ptr<Engine> engine, std::unique_ptr<Brake> brakes, VehicleColour colour)
: this->engine(std::move(engine)),
this->brakes(std::move(brakes)),
this->colour(colour) {
}
virtual void Start(const Key& key) {
engine->ignition( key );
brakes->disengage();
}
virtual void Break( BreakPattern pattern ) {
engine->setThrottlePosition( NO_THROTTLE );
brakes->engage( pattern ); // e.g. SIMPLE_HARMONIC, or SLAM... brakes may have ABS or not but you don't need to know
}
virtual void Accelerate() {
brakes->disengage();
engine->setThrottlePosition( TO_THE_METAL );
}
};
使用它:std::unique_ptr<Brake> absBrakes( new VwAbsDiskBrakes() );
std::unique_ptr<Engine> fastEngine( new TurboV8( FOUR_LITRE ) );
Vehicle hotrod( absBrakes, fastEngine, RED );
hotrod.start();
hotrod.accelerate();
它通过组件的接口使用组件,所以它不需要知道细节。然后,Vehicle的子类不需要担心任何与Vehicle无关的东西。只有当有一辆车不符合你的通用概念时(例如,如果有一辆车没有刹车),你才需要Vehicle的子类。
如何处理略有不同的类?
这完全取决于你要解决的问题。Vehicle
类不是一辆真正的汽车,它是基于现实世界信息的模型,需要制作一个工作程序。它不是一套固定的规则。
关于颜色:这与类的行为无关,所以如果可能的话忽略它,如果不可以,则添加一个额外的字段。
关于发动机的类型:这是否会对行为产生明显的影响,或者只是设置一些参数(功率,耦合,油耗)的问题?在引擎的情况下,您很有可能拥有可以包含在车辆中的引擎层次结构。
- 有没有什么方法可以使用一个函数中定义的常量变量,也可以由c++中同一程序中的其他函数使用
- 与普通变量相比,仅仅读取原子变量的性能有什么不同吗
- 当C++类函数参数之一是结构时,它们的语法有什么不同
- OpenGL中的GL_R8和GL_R8UI有什么不同吗?
- 为什么 c++ 中需要条件来实现良好的编码实践,即使我们没有什么可写的
- 创建变量实例有什么不同?
- C STL,我想知道地图中的双向迭代器和操作员[]之间有什么不同
- C 中(apointer)和A(apointer)之间有什么不同
- Godot扩展C 模块与Android模块.有什么不同
- 静态成员功能和全局功能之间有什么不同
- 关于链表,这两种方法有什么不同?C++中的1个自变量与2个自变量
- 什么是正确的样式来表明没有什么可返回的
- 有没有什么方法可以让窗口出现,但不让SFML中的cmd出现
- arm和x86体系结构中的c/c++语言有什么不同
- std::string的size()和length()有什么不同吗
- 在JNA中,GlobalAlloc和GlobalLock的返回值有什么不同
- 有没有什么方法可以降低时间复杂度来找到这个矩阵的幂n
- 这两个程序有什么不同
- C++模板通过指针的函数/常量指针的函数进行的部分专用化没有什么不同
- 类的类设计几乎没有什么不同