【问题标题】:Right inheritance order正确的继承顺序
【发布时间】:2017-01-15 17:55:03
【问题描述】:

我们需要有轻型/重型汽车的实例和北极轻型/重型汽车的实例。不将ArcticCar代码复制到ArcticLight/HeavyCar中的正确继承(或组合?)方式是什么?

class Car {
    startEnging() {
        turnOnPeripheralDevices();
        checkFuelLevel();
        // + other default actions. Some of them can be overrided in child classes to add specific actions
        log("engine started");
    }
    /* Common car stuff */
}

class LightCar extend Car {
    override startEngine() {
        log("light car prepare to start");
        parent.startEnging();
    }
    /* Basic light car stuff */
}
class HeavyCar extend Car {
    override startEngine() {
        turnOnLights();
        log("heavy car prepare to start");
        parent.startEnging();
    }
    override turnOnPeripheralDevices() {
        parent.turnOnPeripheralDevices(); //Car's default actions
        // additional actions for HeavyCars only
    }
    /* Basic heavy car stuff */
}

class ArcticCar extend Car {
    override startEngine() {
        warmUpEngine()
        wait10seconds();
        log("arctic mode: warming up engine");
        parent.startEnging();
    }
    /* A lot of common stuff for arctic cars. Can overwrite some common Car's functions */
}

class LightArcticCar extend **LightCar, ArcticCar** {
    override startEngine() {
        log("arctic ligh car prepare to start");
        parent.startEnging();
    }
    /* Arctic light car stuff. Can overwrite some specific LightCar's functions */
}
class HeavyArcticCar extend **HeavyCar, ArcticCar** {
    override startEngine() {
        if(checkForecast())
            parent.startEnging();
    }
    override turnOnPeripheralDevices() {
        parent.turnOnPeripheralDevices(); //Car's + HeavyCar's default actions
        // additional actions of HeavyArctic car
    }
    /* Arctic heavy car stuff. Can overwrite some specific HeavyCar's functions */
}

class Main {
    buggy = new LightCar();
    awdSUV = new HeavyCar();

    snowmobile = new ArcticLightCar();
    mobileLaboratory = new ArcticHeavyCar();
}

【问题讨论】:

  • 支持组合胜于继承
  • 可能是装饰器模式的好地方en.wikipedia.org/wiki/Decorator_pattern
  • 除非您在HeavyArcticCar 中明确表示,否则您怎么知道是在预热发动机之前还是之后打开灯?
  • @lhoworko 用于装饰器模式:HeavyArcticCar 必须实现 Car、HeavyCar 和 ArcticCar 类的所有公共方法,即使我只覆盖了一个父类的方法。
  • @jaco0646: HeavyAcrticCar 应该同时扩展 AcrticCarHeavyCar 类:)

标签: java oop inheritance design-patterns


【解决方案1】:

在我看来,处理这种设计的最佳方法是仔细研究问题域。对我来说,看起来你在那里有不止一个实体(汽车)。有引擎、车灯、预测,也许还有其他。 如果是这种情况,更好的设计是为模型中的每个实体设置类:

class Car {
   protected Engine engine;
   protected CarLights carLights;
   void start() {
      engine.start();
   }
}

class Engine {
    void start() { ... }
    void warmUp() { ... } 
}

class CarLights {
   void turnOn() { ... }
}

class Forecast {
   void check() { ... }
}

层次结构将是:

class LightCar extend Car {
    // no code for start

    /* Basic light car stuff */
}

class HeavyCar extend Car{

    void start() {
        carLights.turnOn();
        log("heavy car prepare to start");
        parent.start();
    }

    /* Basic heavy car stuff */
}

class ArcticCar extend   Car {
    void startEngine() {
        engine.warmUp()
        wait10seconds();
        log("arctic mode: warming up engine");
        parent.start();
    }
    /* A lot of common stuff for arctic cars. 
       Can overwrite some common Car's functions */
}

class HeavyArcticCar extend ArcticCar {
    Forecast f; // if it a component of a car. If not, then it should be a local variable in start()
    void start() {

        if( f.check())
            parent.startEnging();
    }
}

OOP 的优点之一是它允许您在代码中为解决手头的问题建模解决方案。

例如,这种情况下的构图要自然得多,它将紧密地反映汽车的真实部件。

另外,还有这个:

https://en.wikipedia.org/wiki/Single_responsibility_principle

所以这里的职责是:

引擎 - 预热和启动代码

CarLights - 打开/关闭车灯的代码

预测 - 要检查的代码

汽车及其衍生产品 - 将上述所有 3 项放在一起并使用它们的功能。

最后一点,可以通过使 Engine、CarLights 和 Forecast 实现一个通用接口(如 CarComponent)来进一步改进设计,因为它们有这个共同点,它们都是汽车组件,并且使用 CarComponent 列表汽车类。这将更加灵活,因为您可以更轻松地添加或删除组件。

【讨论】:

  • 同样的问题:HeavyArcticCar.start() 不会打开灯(所有重型汽车的默认行为)。除了 turnLightOn() 之外,所有重型汽车还有一些其他默认操作。还有HeavySandCar -> SandCar 和其他汽车类和组:(
  • 您可以,因为您在 HeavyArcticCar.start() 方法中显式调用 carLights 实例的 turnOn 方法。另一方面,如果您想处理多个类别并且仅使用继承(或正确的继承顺序,如您在问题中所说)来实现 100% 的代码重用,答案很简单:您不能用单继承。即使在具有多重继承的语言中,你也会得到一个混乱的设计。
  • 我已经更新了主题的代码,可能会更容易看到问题:)HeavyArcticCar同时是HeavyCar和ArcticCar:(ArcticCar是Car,HeavyCar是Car。
  • 所以我不得不将 HeavyCar 或 ArcticCar 的代码复制到 HeavyAcrcticCar、HeavySandCar 和其他 Heavy*Cars。
  • 谢谢!我昨天重新阅读了一些模式和文章.. 并没有找到任何匹配 100% 的案例:(
猜你喜欢
  • 2016-08-09
  • 1970-01-01
  • 2014-09-12
  • 1970-01-01
  • 2011-07-13
  • 2016-11-05
  • 1970-01-01
  • 2015-12-27
  • 1970-01-01
相关资源
最近更新 更多