Oop 如何将合成与继承结合使用?

Oop 如何将合成与继承结合使用?,oop,inheritance,composition,ooad,car-analogy,Oop,Inheritance,Composition,Ooad,Car Analogy,我将试着在一个简单的例子中提出我的问题 假设我有一辆抽象的基类汽车。汽车有一个基本的引擎对象。我在抽象的Car类中有一个StartEngine()方法,它将引擎的启动委托给engine对象 我如何允许汽车的子类(如法拉利)将引擎对象声明为特定类型的引擎(例如涡轮发动机)?我需要另一个汽车级别(涡轮汽车)吗 我继承了一个普通的老Engine对象,不能在我的Car子类中将其重新声明(或重写)为TurboEngine 编辑:我知道我可以将引擎的任何子类插入我的法拉利类中的myEngine引用中……但是

我将试着在一个简单的例子中提出我的问题

假设我有一辆抽象的基类汽车。汽车有一个基本的引擎对象。我在抽象的Car类中有一个StartEngine()方法,它将引擎的启动委托给engine对象

我如何允许汽车的子类(如法拉利)将引擎对象声明为特定类型的引擎(例如涡轮发动机)?我需要另一个汽车级别(涡轮汽车)吗

我继承了一个普通的老Engine对象,不能在我的Car子类中将其重新声明(或重写)为TurboEngine

编辑:我知道我可以将引擎的任何子类插入我的法拉利类中的myEngine引用中……但是我如何调用只有涡轮引擎公开的方法呢?因为myEngine是作为基础引擎继承的,所以不包括任何turbo内容


谢谢

有很多方法可以做到这一点


我倾向于在
Car
上使用
setEngine()
方法,然后让
Ferrari
构造函数调用
setEngine()
,并传入一个
TurboEngine

的实例,抽象工厂模式正是针对这个问题的。谷歌GoF抽象工厂{您的首选语言}

class Program
{
    static void Main(string[] args)
    {
        Ferrari ferarri = new Ferrari();
        ferarri.Start();
        ferarri.Boost();
    }
}
public class Car<EngineType> where EngineType : Engine, new()
{
    protected EngineType engine;

    public Car()
    {
        this.CreateEngine();
    }
    protected void CreateEngine()
    {
        this.engine = new EngineType();
    }
    public void Start()
    {
        engine.Start();
    }
}

public class Ferrari : Car<TurboEngine>
{
    public void Boost()
    {
        engine.Boost();
    }
}

public class Engine
{
    public virtual void Start()
    {
        Console.WriteLine("Vroom!");
    }
}
public class TurboEngine : Engine
{
    public void Boost()
    {
        Console.WriteLine("Hang on to your teeth...");
    }
    public override void Start()
    {
        Console.WriteLine("VROOOOM! VROOOOM!");
    }
}
在下文中,请注意如何使用混凝土工厂生产“完整”对象(enzo、civic)或使用它们生产相关对象的“系列”(CarbonFrame+涡轮发动机、WeakFrame+发动机)。最终,您总会得到一个Car对象,该对象以特定于类型的行为响应accelerate()



不要在接口中公开类的内部内容——换句话说,Car的公共方法应该是Start,而不是StartEngine

如果您想要强加一个内部结构(例如,只有一个引擎),那么您需要另一个可以专门化的抽象/基类引擎

然后,通过将m_engine成员设置为engine的运动子类等,您可以用零件构造一辆跑车

编辑:请注意,在现实世界中,涡轮增压器不是发动机的一部分,它是发动机的附加组件,具有自己的控制界面。。。但是如果你想在你的法拉利引擎中包含这样的东西,没关系,只要在跑车子类中向上转换,使你的基本引擎变成涡轮引擎


但最好的建模方法是将部件分开,这样您就可以升级涡轮增压器(例如,双进气与单进气),而无需更换整个发动机

根据您特定的语言语义,有几种方法可以做到这一点。即兴发挥,我最初的想法是提供一个受保护的构造函数:

public class Car {
    private Engine engine;

    public Car() {
        this(new Engine());
    }

    protected Car(Engine engine) {
        this.engine = engine;
    }

    public void start() {
        this.engine.start();
    }
}

public class Ferrari {
    public Ferrari() {
        super(new TurboEngine());
    }
}

只要涡轮发动机是发动机的一个子类,就不需要指定汽车的一个子类来拥有涡轮发动机。您可以指定涡轮发动机的一个实例作为法拉利的发动机。你甚至可以在你的法拉利里放一个柴油发动机。它们都只是引擎

汽车有发动机。涡轮发动机是一种发动机。汽车可以有涡轮发动机、柴油发动机或燧石发动机。它们都是引擎

如果您想限制Car子类中的引擎类型(跑车中没有割草机引擎),可以将其声明为Engine,并在setter方法中对其进行限制


汽车与引擎的关系并不限制引擎的适用子类。

您可以始终使用受保护的摘要。公共“Start”将调用protected(即抽象类中的ovveride)。这样,调用方只能看到Start()而不能看到StartEngine()

-使用方法:

Car c = new Ferrari();
c.Start();

我想这会管用的

public class Car
{
    private Engine engine;
    public virtual Engine CarEngine
    {
        get { return engine;}
    }

    public StartEngine()
    {
         CarEngine.Start();
    }
}

public class Engine
{
     public virtual void Start()
     {
         Console.Writeline("Vroom");
     }
} 

public class TurboEngine : Engine
{
    public override void Start()
    {
        Console.Writeline("Vroom pSHHHHHHH");
    }    

    // TurboEngine Only method
    public double BoostPressure()
    {
    }
}

public class Ferrari : Car
{
    private TurboEngine engine;
    public override Engine CarEngine
    {
         return engine;
    }
}

Ferrari = car new Ferrari();
// Will call Start on TurboEngine()
car.StartEngine();
// Upcast to get TurboEngine stuff
Console.WriteLine(car.CarEngine as TurboEngine).BoostPressure();

你的语言中有泛型吗?在Java中,我可以这样做:

class Engine {}

abstract class Car<E extends Engine> 
{
    private E engine;
    public E getEngine() { return engine; } 
}

class TurboEngine extends Engine {}

class Ferrari extends Car<TurboEngine> 
{
    // Ferrari now has a method with this signature:
    // public TurboEngine getEngine() {} 
}
类引擎{}
抽象类汽车
{
私人电子引擎;
public E getEngine(){return engine;}
}
类TurboEngine扩展引擎{}
法拉利级轿车
{
//法拉利现在有了一个具有此签名的方法:
//公共涡轮发动机getEngine(){}
}
我相信C#中也有类似的东西。然后,您可以将法拉利实例视为法拉利子类的实例(getEngine返回涡轮发动机)或汽车超类的实例(当getEngine返回发动机时)。

您可以使用C#泛型来获取所需内容,这里

使用泛型的区别在于,您的
法拉利
知道其
发动机
是一个
涡轮发动机
,而
汽车
类不必知道任何新的东西,只要
发动机类型
发动机

class Program
{
    static void Main(string[] args)
    {
        Ferrari ferarri = new Ferrari();
        ferarri.Start();
        ferarri.Boost();
    }
}
public class Car<EngineType> where EngineType : Engine, new()
{
    protected EngineType engine;

    public Car()
    {
        this.CreateEngine();
    }
    protected void CreateEngine()
    {
        this.engine = new EngineType();
    }
    public void Start()
    {
        engine.Start();
    }
}

public class Ferrari : Car<TurboEngine>
{
    public void Boost()
    {
        engine.Boost();
    }
}

public class Engine
{
    public virtual void Start()
    {
        Console.WriteLine("Vroom!");
    }
}
public class TurboEngine : Engine
{
    public void Boost()
    {
        Console.WriteLine("Hang on to your teeth...");
    }
    public override void Start()
    {
        Console.WriteLine("VROOOOM! VROOOOM!");
    }
}
类程序
{
静态void Main(字符串[]参数)
{
法拉利法拉利=新法拉利();
ferarri.Start();
ferarri.Boost();
}
}
公共级汽车,其中EngineType:Engine,new()
{
受保护的引擎类型引擎;
公共汽车
{
这个.CreateEngine();
}
受保护的void CreateEngine()
{
this.engine=新的EngineType();
}
公开作废开始()
{
发动机起动();
}
}
公共级法拉利:汽车
{
公共图书馆
{
发动机。增压();
}
}
公共级引擎
{
公共虚拟void Start()
{
控制台。WriteLine(“Vroom!”);
}
}
公共级涡轮发动机:发动机
{
公共图书馆
{
控制台。WriteLine(“咬紧牙关…”);
}
公共覆盖无效开始()
{
控制台。WriteLine(“Vrooom!Vrooom!”);
}
}
根据我对你(更新)问题的理解,如果你想调用
涡轮发动机
方法,你必须将汽车发动机转换为
涡轮发动机
类型。在调用这些方法之前,需要进行大量检查,以查看您的汽车是否有
涡轮发动机,但这就是您得到的结果。我不知道这辆车到底代表什么,我想不出任何理由你不能拥有它
class Program
{
    static void Main(string[] args)
    {
        Ferrari ferarri = new Ferrari();
        ferarri.Start();
        ferarri.Boost();
    }
}
public class Car<EngineType> where EngineType : Engine, new()
{
    protected EngineType engine;

    public Car()
    {
        this.CreateEngine();
    }
    protected void CreateEngine()
    {
        this.engine = new EngineType();
    }
    public void Start()
    {
        engine.Start();
    }
}

public class Ferrari : Car<TurboEngine>
{
    public void Boost()
    {
        engine.Boost();
    }
}

public class Engine
{
    public virtual void Start()
    {
        Console.WriteLine("Vroom!");
    }
}
public class TurboEngine : Engine
{
    public void Boost()
    {
        Console.WriteLine("Hang on to your teeth...");
    }
    public override void Start()
    {
        Console.WriteLine("VROOOOM! VROOOOM!");
    }
}