Frage

Ich werde versuchen, meine Frage im Zusammenhang mit einem einfachen Beispiel fragen ...

Lassen Sie uns sagen, ich habe eine abstrakte Basisklasse-Auto. Auto hat-ein grundlegenden Motor Objekt. Ich habe eine Methode StartEngine () in der abstrakten Klasse Car, dass die Delegierten das Starten des Motors auf den Motor Objekt.

Wie ermögliche ich Subklassen von Auto (wie Ferrari), um den Motor Objekt als eine bestimmte Art von Motor zu erklären (beispielsweise Turbomotor)? Muss ich eine andere Klasse Car (TurboCar)?

Ich bin ein plain old-Engine-Objekt erben, und ich kann nicht wieder declare (oder außer Kraft setzen) es als Strömungsmaschine in meinem Auto Subklassen.

EDIT: Ich verstehe, dass ich jede Unterklasse von Engine in myEngine Referenz in meinem Ferrari Klasse stecken kann ... aber wie kann ich Methoden aufrufen, die nur die Strömungsmaschine aussetzt? Da myEngine als Basis-Engine, keiner der Turbo Sachen geerbt ist im Preis inbegriffen.

Danke!

War es hilfreich?

Lösung

Die Abstrakte Fabrik ist genau für dieses Problem. Google GoF Abstract Factory {Ihre bevorzugte Sprache}

Im Folgenden beachten Sie, wie Sie entweder die konkreten Fabriken verwenden können „vollständig“ Objekte (enzo, bürgerlichen) zu erzeugen, oder Sie können sie verwenden, um „Familien“ von verwandten Objekten zu erzeugen (CarbonFrame + Turbotriebwerk, WeakFrame + WeakEngine). Letztlich Sie immer mit einem Car-Objekt am Ende, die () mit typspezifischen Verhalten zu beschleunigen reagiert.


     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();
        }
    }

Andere Tipps

Es gibt keine Notwendigkeit, eine Unterklasse von Auto zu erhalten, eine Strömungsmaschine zu haben, solange Strömungsmaschine eine Unterklasse von Engine ist. Sie können nur eine Instanz von Strömungsmaschine als Motor für Ihren Ferrari angeben. Man könnte sogar einen Dieselmotor in Ihrem Ferrari setzen. Sie sind alle nur Motoren.

Ein Auto hat einen Motor. Ein Turbomotor ist ein Motor. Ein Auto kann einen Turbomotor oder einen Dieselmotor oder ein FlintstonesEngine. Sie sind alle Motoren.

Wenn Sie die Art von Motor in Ihrem Auto-Unterklasse (kein LawnMowerEngine in einem SportsCar) beschränken möchten, können Sie es als Motor verlassen erklärt und es in den Setter-Methoden beschränken.

Das Auto hat einen Motor Beziehung hat die geltenden Subklassen von Motor nicht begrenzen.

Sie können jederzeit eine abstrakte verwenden, die geschützt ist. Die Öffentlichkeit „Start“ wird der geschützte nennen (das in der abstrakten Klasse ovveride wird). Auf diese Weise der Anrufer nur den Start () und nicht die StartEngine () sehen.

abstract class Car {
    private Engine engine;

    public Car() {
        this.engine = new Engine();
    }

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

    public void Start()
    {
        this.StartEngine();
    }
    protected abstract void StartEngine();
}

public class Ferrari : Car
{
    public Ferrari() {

    }
    protected override void StartEngine()
    {
        Console.WriteLine("TURBO ENABLE!!!");
    }

}

-Der Weg, es zu verwenden:

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

Ich denke, das würde funktionieren.

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();

Sie können C # Generika verwenden zu bekommen, was Sie suchen, hier.

Die Unterscheidung Generika ist, dass Ihr Ferrari „weiß“, dass sein Engine ist-ein TurboEngine, während die Car Klasse nichts Neues-nur wissen, hat die EngineType ist-ein 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!");
    }
}

Wie ich Ihre (aktualisiert) Frage zu verstehen, sind Sie gehen zu müssen das Auto Motor auf die TurboEngine Art werfen, wenn Sie TurboEngine Methoden auf sie anrufen möchten. Das ergibt eine Menge zu überprüfen, ob das Auto haben Sie eine TurboEngine hat, bevor Sie diese Methoden aufrufen, aber das ist, was man bekommt. Nicht zu wissen, was das Auto tatsächlich in steht für, kann ich mich keinen Grund, warum Sie nicht den Motor und die Turbo-Motor die gleiche Schnittstelle haben könnten - gibt es wirklich neue Methoden, die die Turbo unterstützt, oder tut es einfach tun die gleichen Dinge anders - aber ich denke, diese Metapher auseinander früher oder später fallen würde

.

Haben Sie Generika in Ihrer Sprache haben? In Java könnte ich dies tun:

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() {} 
}

Ich bin sicher, dass es etwas ähnliches in C #. Sie können dann eine Instanz von Ferrari behandeln, als entweder eine Instanz der Unterklasse Ferrari (mit getEngine die Strömungsmaschine Rückkehr) oder als eine Instanz des Autosuper (wenn getEngine wird ein Motor zurück).

auf Ihrer spezielle Sprachsemantik Je, es gibt ein paar Möglichkeiten, dies zu tun. Aus der Manschette wäre mein erster Gedanke, einen geschützten Konstruktor zur Verfügung zu stellen:

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());
    }
}

Bestrahlung der Interna der Klasse in der Schnittstelle - mit anderen Worten, sollte die öffentliche Methode Auto seinen Start, nicht StartEngine

Wenn Sie eine interne Struktur aufzwingen wollen (das heißt, wie es nur ein Motor mit), dann müssen Sie eine andere abstrakte / Basisklasse Motor, die spezialisiert werden kann.

, dann können Sie einen Sportwagen aus Teilen konstruieren, indem das m_engine Mitglieds zu einer sportlichen Unterklasse von Motoreinstellung, et al

EDIT: beachten Sie, dass in der realen Welt, ein Turbolader nicht Teil des Motors ist, ist es ein Add-On zu dem Motor, mit einer eigenen Bedienoberfläche ... Aber wenn Sie Dinge wie diese sind in Ihrem Ferrari-Motor, das ist in Ordnung, nur upcast in der SportsCar Unterklasse Ihre Basis-Engine in eine Strömungsmaschine

zu machen

aber es wäre besser Modellierung werden die Komponenten getrennt zu halten - auf diese Weise Sie Ihren Turbolader (Dual Aufnahme vs einzelne Aufnahme, zum Beispiel) aktualisieren können, ohne den gesamten Motor ersetzen

Es gibt viele Möglichkeiten, es getan werden könnte.

Ich würde bevorzugen setEngine() Methode auf Car hat, dann den Ferrari Konstruktoraufruf setEngine() mit und in einer Instanz eines TurboEngine passieren.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top