2008-11-10 27 views
7

मैं एक साधारण उदाहरण के संदर्भ में अपने प्रश्न पूछने की कोशिश करने जा रहा हूं ...मैं विरासत के साथ संरचना का उपयोग कैसे करूं?

मान लें कि मेरे पास एक सार बेस क्लास कार है। कार में एक मूल इंजन वस्तु है। मेरे पास सार कार श्रेणी में StartEngine() है जो इंजन की इंजन इंजन से शुरू करने का प्रतिनिधि है।

मैं इंजन ऑब्जेक्ट को एक विशिष्ट प्रकार के इंजन (उदा।, टर्बोइंजिन) के रूप में घोषित करने के लिए कार (जैसे फेरारी) के उप-वर्गों को कैसे अनुमति दूं? क्या मुझे एक और कार वर्ग (टर्बोकार) चाहिए?

मैं एक सादे पुराने इंजन ऑब्जेक्ट को विरासत में मिला हूं और मैं इसे अपने कार उप-वर्गों में टर्बोइंजिन के रूप में पुन: घोषित नहीं कर सकता (या ओवरराइड) नहीं कर सकता।

संपादित करें: मैं समझता हूँ कि मैं अपने फेरारी वर्ग के भीतर myEngine संदर्भ में इंजन के किसी भी उपवर्ग प्लग कर सकते हैं ... लेकिन मैं तरीकों केवल TurboEngine को उजागर करता है कि कैसे फोन कर सकते हैं? चूंकि myEngine को बेस इंजन के रूप में विरासत में मिला है, इसलिए टर्बो सामान में से कोई भी शामिल नहीं है।

धन्यवाद!

+0

ओहोह! आश्चर्यजनक! कभी नहीं पता था कि एसओ में एक * कार-अनुरूप * टैग था! –

उत्तर

9

सार फैक्टरी पैटर्न इस समस्या के लिए बिल्कुल ठीक है। Google गोफ सार फैक्टरी {आपकी पसंदीदा भाषा}

निम्नलिखित में, ध्यान दें कि आप या तो "पूर्ण" ऑब्जेक्ट्स (इंजो, सिविक) बनाने के लिए ठोस कारखानों का उपयोग कैसे कर सकते हैं या आप उन्हें संबंधित वस्तुओं के "परिवार" बनाने के लिए उपयोग कर सकते हैं (कार्बनफ्रेम + टर्बोइंजिन, वीकफ्रेम + वीकइंजिन)। आखिरकार, आप हमेशा एक कार ऑब्जेक्ट के साथ समाप्त होते हैं जो टाइप-विशिष्ट व्यवहार के साथ() को तेज करने का जवाब देता है।


 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

बहुत सारे तरीके किए जा सकते हैं।

मैं Car पर एक setEngine() विधि है, तो Ferrari निर्माता कॉल setEngine() होने और एक TurboEngine का एक उदाहरण में पारित एहसान होगा।

0

इंटरफ़ेस में अपने वर्ग के आंतरिक भागों के संपर्क में न - दूसरे शब्दों में, कार की सार्वजनिक विधि, प्रारंभ होना चाहिए StartEngine नहीं

अगर आप एक आंतरिक संरचना को लागू करना चाहते हैं (यानी केवल 1 इंजन होने की तरह) तो आपको एक और सार/बेस क्लास इंजन की आवश्यकता है जिसे विशेषीकृत किया जा सके।

तो आप एक स्पोर्ट्स कार भागों से बाहर m_engine सदस्य की स्थापना करके इंजन के एक स्पोर्टी उपवर्ग, करने के लिए निर्माण कर सकते हैं एट अल

संपादित करें: ध्यान दें कि असली दुनिया में, एक टर्बोचार्जर इंजन का हिस्सा नहीं है, यह इंजन पर एक एड-ऑन है, अपने नियंत्रण इंटरफ़ेस के साथ ... लेकिन यदि आप अपने फेरारी इंजन में इस तरह की चीजें शामिल करना चाहते हैं, तो ठीक है, स्पोर्ट्सकर सबक्लास में बस अपने बेस इंजन को टर्बोइंजिन

में बनाने के लिए बस

लेकिन यह घटकों को अलग रखने के लिए बेहतर मॉडलिंग होगा - इस तरह आप पूरे इंजन को बदलने के बिना अपने टर्बोचार्जर (उदाहरण के लिए दोहरी सेवन बनाम एकल सेवन) को अपग्रेड कर सकते हैं!

+0

@ vg1890: संपादन देखें; एक टर्बोचार्जर इंजन का हिस्सा नहीं है, यह एक और घटक है जो इंजन के साथ काम करता है –

1

आपकी विशेष भाषा अर्थशास्त्र के आधार पर, ऐसा करने के कुछ तरीके हैं।

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

जब तक TurboEngine इंजन का एक उपवर्ग है एक TurboEngine के लिए कार का एक उपवर्ग निर्दिष्ट करने के लिए कोई ज़रूरत नहीं है: कफ बंद मेरी प्रारंभिक सोचा एक संरक्षित निर्माता प्रदान करने के लिए किया जाएगा। आप अपने फेरारी के इंजन के रूप में टर्बोइंजिन का एक उदाहरण निर्दिष्ट कर सकते हैं। आप अपने फेरारी में एक डीजलइंजिन भी डाल सकते हैं। वे सब सिर्फ इंजन हैं।

ए कार में एक इंजन है। एक टर्बोइंजिन एक इंजन है। एक कार में टर्बोइंजिन या डीज़ेलइंजिन या फ्लिंटस्टोनइंजिन हो सकता है। वे सभी इंजन हैं।

यदि आप अपने कार उपclass (किसी स्पोर्ट्सकार में लॉनमोवरइंजिन) में इंजन के प्रकार को सीमित करना चाहते हैं, तो आप इसे इंजन के रूप में घोषित कर सकते हैं और इसे सेटटर विधियों में सीमित कर सकते हैं।

कार का इंजन संबंध इंजन के लागू उप-वर्गों को सीमित नहीं करता है।

2

आप हमेशा संरक्षित एक सार का उपयोग कर सकते हैं। सार्वजनिक "स्टार्ट" संरक्षित कॉल करेगा (जो अमूर्त वर्ग में ओवरवेइड होगा)। इस तरह कॉलर केवल स्टार्ट() को प्रारंभ करता है और स्टार्टइंजिन() नहीं।

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!!!"); 
    } 

} 

-इस तरह से इसका इस्तेमाल करने की:

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

मुझे लगता है कि यह काम करेगा।

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

क्या आपके पास अपनी भाषा में जेनेरिक हैं? जावा में मैं यह कर सकता था:

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

मुझे यकीन है कि सी # में कुछ समान है। इसके बाद आप फेरारी के एक उदाहरण के रूप में फेरारी सबक्लास (टर्बोइंजिन लौटने वाली गेटइंजिन के साथ) या कार सुपरक्लास के उदाहरण के रूप में (जब GetEngine इंजन वापस कर देगा) के उदाहरण के रूप में फेरारी के एक उदाहरण का इलाज कर सकते हैं।

1

आप जो कुछ भी ढूंढ रहे हैं उसे पाने के लिए आप सी # जेनेरिक का उपयोग कर सकते हैं।

जेनरिक का उपयोग करने का गौरव प्राप्त है कि आपके Ferrari "जानता" है कि इसके Engine है-एक TurboEngine, जबकि Car वर्ग कुछ भी नया — ही नहीं EngineType है-एक 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!"); 
    } 
} 
1

जैसा कि मैंने अपने (अद्यतन) प्रश्न को समझते हैं, आप TurboEngine प्रकार के कार के इंजन कास्ट करने के लिए करने जा रहे हैं, तो आप उस पर TurboEngine तरीकों कॉल करना चाहते हैं। इसके परिणामस्वरूप आप यह देखने के लिए बहुत सारी जांच कर रहे हैं कि आपके पास उन विधियों को कॉल करने से पहले TurboEngine है, लेकिन यह वही है जो आपको मिलता है। यह जानकर कि यह कार वास्तव में किसके लिए खड़ी है, मैं किसी भी कारण से नहीं सोच सकता कि आपके पास इंजन नहीं हो सकता है और टर्बो इंजन एक ही इंटरफ़ेस साझा करता है - क्या वास्तव में टर्बो का समर्थन करने वाले नए तरीके हैं, या यह करता है वही चीजें अलग-अलग हैं - लेकिन मुझे लगता है कि यह रूपक जल्द या बाद में अलग हो जाएगा।

संबंधित मुद्दे