How do I use composition with inheritance?

前端 未结 10 2400
星月不相逢
星月不相逢 2021-02-09 04:41

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

相关标签:
10条回答
  • 2021-02-09 05:22

    You can use C# generics to get what you're looking for, here.

    The distinction of using generics is that your Ferrari "knows" that its Engine is-a TurboEngine, while the Car class doesn't have to know anything new—only that EngineType is-an Engine.

    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!");
        }
    }
    
    0 讨论(0)
  • 2021-02-09 05:28

    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:

    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());
        }
    }
    
    0 讨论(0)
  • 2021-02-09 05:30

    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 call TurboEngine methods on it. That results in a lot of checking to see if the car you have has a TurboEngine 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.

    0 讨论(0)
  • 2021-02-09 05:33

    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.


         using System;
    
    
        abstract class CarFactory
        {
            public static CarFactory FactoryFor(string manufacturer){
                switch(manufacturer){
                    case "Ferrari" : return new FerrariFactory();
                    case "Honda" : return new HondaFactory();
                    default:
                        throw new ArgumentException("Unknown car manufacturer. Please bailout industry.");
                }
            }
    
            public abstract Car createCar();
            public abstract Engine createEngine();
            public abstract Frame createFrame();
    
        }
    
        class FerrariFactory : CarFactory
        {
            public override Car createCar()
            {
                return new Ferrari(createEngine(), createFrame());
            }
    
            public override Engine createEngine()
            {
                return new TurboEngine();
            }
    
            public override Frame createFrame()
            {
                return new CarbonFrame();
            }
        }
    
        class HondaFactory : CarFactory
        {
            public override Car createCar()
            {
                return new Honda(createEngine(), createFrame());
            }
    
            public override Engine createEngine()
            {
                return new WeakEngine();
            }
    
            public override Frame createFrame()
            {
                return new WeakFrame();
            }
        }
    
        abstract class Car
        {
            private Engine engine;
            private Frame frame;
    
            public Car(Engine engine, Frame frame)
            {
                this.engine = engine;
                this.frame = frame;
            }
    
            public void accelerate()
            {
                engine.setThrottle(1.0f);
                frame.respondToSpeed();
            }
    
        }
    
        class Ferrari : Car
        {
            public Ferrari(Engine engine, Frame frame) : base(engine, frame)
            {
                Console.WriteLine("Setting sticker price to $250K");
            }
        }
    
        class Honda : Car
        {
            public Honda(Engine engine, Frame frame) : base(engine, frame)
            {
                Console.WriteLine("Setting sticker price to $25K");
            }
        }
    
        class KitCar : Car
        {
            public KitCar(String name, Engine engine, Frame frame)
                : base(engine, frame)
            {
                Console.WriteLine("Going out in the garage and building myself a " + name);
            }
        }
    
        abstract class Engine
        {
            public void setThrottle(float percent)
            {
                Console.WriteLine("Stomping on accelerator!");
                typeSpecificAcceleration();
            }
    
            protected abstract void typeSpecificAcceleration();
        }
    
        class TurboEngine : Engine
        {
            protected override void typeSpecificAcceleration()
            {
                Console.WriteLine("Activating turbo");
                Console.WriteLine("Making noise like Barry White gargling wasps");
            }
        }
    
        class WeakEngine : Engine
        {
            protected override void typeSpecificAcceleration()
            {
                Console.WriteLine("Provoking hamster to run faster");
                Console.WriteLine("Whining like a dentist's drill");
            }
        }
    
        abstract class Frame
        {
            public abstract void respondToSpeed();
        }
    
        class CarbonFrame : Frame
        {
            public override void respondToSpeed()
            {
                Console.WriteLine("Activating active suspension and extending spoilers");
            }
        }
    
        class WeakFrame : Frame
        {
            public override void respondToSpeed()
            {
                Console.WriteLine("Loosening bolts and vibrating");
            }
        }
    
        class TestClass
        {
            public static void Main()
            {
                CarFactory ferrariFactory = CarFactory.FactoryFor("Ferrari");
                Car enzo = ferrariFactory.createCar();
                enzo.accelerate();
    
                Console.WriteLine("---");
                CarFactory hondaFactory = CarFactory.FactoryFor("Honda");
                Car civic = hondaFactory.createCar();
                civic.accelerate();
    
                Console.WriteLine("---");
                Frame frame = hondaFactory.createFrame();
                Engine engine = ferrariFactory.createEngine();
                Car kitCar = new KitCar("Shaker", engine, frame);
                kitCar.accelerate();
    
                Console.WriteLine("---");
                Car kitCar2 = new KitCar("LooksGreatGoesSlow", hondaFactory.createEngine(), ferrariFactory.createFrame());
                kitCar2.accelerate();
            }
        }
    
    0 讨论(0)
提交回复
热议问题