如何将组合与继承结合使用?
我将尝试在一个简单的示例中提出我的问题......
假设我有一个抽象基类 Car。 汽车有一个基本的 Engine 对象。 我在抽象 Car 类中有一个 StartEngine() 方法,它将引擎的启动委托给 Engine 对象。
如何允许 Car 的子类(例如 Ferrari)将 Engine 对象声明为特定类型的引擎(例如 TurboEngine)? 我需要另一个 Car 类 (TurboCar) 吗?
我继承了一个普通的旧 Engine 对象,并且无法在我的 Car 子类中将其重新声明(或重写)为 TurboEngine。
编辑:我知道我可以将 Engine 的任何子类插入到我的 Ferrari 类中的 myEngine 引用中...但是我如何调用只有 TurboEngine 公开的方法? 因为 myEngine 是作为基础 Engine 继承的,所以不包含任何 Turbo 的东西。
谢谢!
I'm going to try to ask my question in the context of a simple example...
Let's say I have an abstract base class Car. Car has-a basic Engine object. I have a method StartEngine() in the abstract Car class that delegates the starting of the engine to the Engine object.
How do I allow subclasses of Car (like Ferrari) to declare the Engine object as a specific type of engine (e.g., TurboEngine)? Do I need another Car class (TurboCar)?
I'm inheriting a plain old Engine object and I cannot re-declare (or override) it as a TurboEngine in my Car subclasses.
EDIT: I understand that I can plug any subclass of Engine into myEngine reference within my Ferrari class...but how can I call methods that only the TurboEngine exposes? Because myEngine is inherited as a base Engine, none of the turbo stuff is included.
Thanks!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(10)
抽象工厂模式正是针对这个问题。 Google GoF Abstract Factory {您的首选语言}
在下文中,请注意如何使用具体工厂来生成“完整”对象(enzo、civic),或者使用它们来生成相关对象的“家族”(CarbonFrame + TurboEngine) ,WeakFrame + WeakEngine)。 最终,您总是会得到一个 Car 对象,该对象以特定于类型的行为响应 Accelerate() 。
The Abstract Factory pattern is precisely for this problem. Google GoF Abstract Factory {your preferred language}
In the following, note how you can either use the concrete factories to produce "complete" objects (enzo, civic) or you can use them to produce "families" of related objects (CarbonFrame + TurboEngine, WeakFrame + WeakEngine). Ultimately, you always end up with a Car object that responds to accelerate() with type-specific behavior.
只要 TurboEngine 是 Engine 的子类,就不需要指定 Car 的子类来拥有 TurboEngine。 您只需指定 TurboEngine 的一个实例作为您的 Ferrari 的引擎。 您甚至可以在您的法拉利中安装柴油发动机。 他们都只是引擎。
汽车有发动机。 TurboEngine 是一个引擎。 汽车可以有涡轮发动机、柴油发动机或燧石发动机。 他们都是引擎。
如果您想限制 Car 子类中的 Engine 类型(SportsCar 中没有 LawnMowerEngine),您可以将其声明为 Engine 并在 setter 方法中限制它。
Car 与 Engine 的关系并不限制 Engine 的适用子类。
There's no need to specify a subclass of Car to have a TurboEngine as long as TurboEngine is a subclass of Engine. You can just specify an instance of TurboEngine as the Engine for your Ferrari. You could even put a DieselEngine in your Ferrari. They're all just Engines.
A Car has an Engine. A TurboEngine is an Engine. A Car can have a TurboEngine or a DieselEngine or a FlintstonesEngine. They're all Engines.
If you want to limit the type of Engine in your Car subclass (no LawnMowerEngine in a SportsCar), you can leave it declared as Engine and limit it in the setter methods.
The Car has an Engine relationship doesn't limit the applicable subclasses of Engine.
您始终可以使用受保护的摘要。 公共“Start”将调用受保护的(将在抽象类中被 ovveride )。 这样调用者只能看到 Start() 而看不到 StartEngine()。
- 使用方法:
You can always use an abstract that is protected. The public "Start" will call the protected (that will be ovveride in the abstract class). This way the caller only see the Start() and not the StartEngine().
-The way to use it:
我认为这会起作用。
I think this would work.
您可以在此处使用 C# 泛型来获取您要查找的内容。
使用泛型的区别在于,您的
Ferrari
“知道”其Engine
是TurboEngine
,而Car
> 类不必知道任何新内容,只需知道EngineType
是一个Engine
。You can use C# generics to get what you're looking for, here.
The distinction of using generics is that your
Ferrari
"knows" that itsEngine
is-aTurboEngine
, while theCar
class doesn't have to know anything new—only thatEngineType
is-anEngine
.据我了解您的(更新的)问题,如果您想调用汽车的
TurboEngine
方法,则必须将汽车的发动机转换为TurboEngine
类型。 这会导致在调用这些方法之前进行大量检查,看看您的汽车是否有TurboEngine
,但这就是您得到的结果。 不知道这辆车实际上代表什么,我想不出有什么理由不能让发动机和涡轮发动机共享相同的接口 - 涡轮是否真的支持新方法,或者只是这样做同样的事情有不同的方式——但我想这个比喻迟早会崩溃。As I understand your (updated) question, you're going to have to cast the car's engine to the
TurboEngine
type if you want to callTurboEngine
methods on it. That results in a lot of checking to see if the car you have has aTurboEngine
before you call those methods, but that's what you get. Not knowing what this car is actually standing in for, I can't think of any reason you couldn't have the engine and the turbo engine share the same interface - are there really new methods that the turbo supports, or does it just do the same things differently - but I guess this metaphor was going to fall apart sooner or later.你的语言有泛型吗? 在 Java 中我可以这样做:
我确信 C# 中也有类似的东西。 然后,您可以将 Ferrari 的实例视为 Ferrari 子类的实例(getEngine 返回 TurboEngine)或 Car 超类的实例(当 getEngine 将返回 Engine)。
Do you have generics in your language? In Java I could do this:
I'm sure there's something similar in C#. You can then treat an instance of Ferrari as either an instance of the Ferrari subclass (with getEngine returning the TurboEngine) or as an instance of the Car superclass (when getEngine will return an Engine).
根据您的特定语言语义,有几种方法可以做到这一点。 我最初的想法是提供一个受保护的构造函数:
Depending on your particular language semantics, there are a few ways to do this. Off the cuff my initial thought would be to provide a protected constructor:
不要在接口中公开类的内部结构 - 换句话说,
如果您想强加一个内部结构(即只有 1 个引擎),那么 Car 的公共方法应该是 Start,而不是 StartEngine,那么您需要另一个抽象/可以专门化的基类引擎。
然后你可以通过将 m_engine 成员设置为 Engine 的运动子类来构造一辆跑车,等等
编辑:请注意,在现实世界中,涡轮增压器不是发动机的一部分,它是发动机的附加组件引擎,有自己的控制界面...但是如果你想在你的法拉利引擎中包含这样的东西,那没关系,只需在 SportsCar 子类中向上转换,使你的基本引擎变成 TurboEngine,
但最好建模以保留组件分开 - 这样您就可以升级您的涡轮增压器(例如双进气与单进气),而无需更换整个发动机!
don't expose the internals of your class in the interface - in other words, the public method of Car should be Start, not StartEngine
if you want to impose an internal structure (i.e. like having only 1 engine) then you need another abstract/base class Engine that can be specialized.
then you can construct a sports car out of parts by setting the m_engine member to a sporty subclass of Engine, et al
EDIT: note that in the real world, a turbocharger is not part of the engine, it is an add-on to the engine, with its own control interface... But if you want to include things like this in your ferrari engine, that's ok, just upcast in the SportsCar subclass to make your base Engine into a TurboEngine
but it would be better modeling to keep the components separate - that way you can upgrade your turbocharger (dual intake vs single intake, for example) without replacing the entire engine!
有很多方法可以做到。
我希望在
Car
上使用setEngine()
方法,然后让Ferrari
构造函数调用setEngine()
并传入TurboEngine
的实例。There are lots of ways it could be done.
I would favour having a
setEngine()
method onCar
, then having theFerrari
constructor callsetEngine()
and pass in an instance of aTurboEngine
.