我可以通过使用一个超类扩展到另一个超类来创建继承的层次结构吗?

所以我们正在做一个虚拟宠物项目,我们需要创建ArrayList并与虚拟宠物交互。

我想做的是拥有一个可扩展到CatClass和DogClass的PetClass超类。
CatClass将是OrganicCat和RoboticCat的超类。狗类也是如此。

这可能吗?或者我应该使用抽象方法还是继承方法?

我找不到任何问题或答案,因此假定这是不可能的。


解决方案

您可以想出这样的东西

然而,有一个更好的解决方案。您可以在这里看到这个设计由7个类和一个接口组成。在该图中,CatDog可以(也可能应该)是一个抽象类。这种设计的缺点是类爆炸。假设您需要添加一个WildDog。首先,您需要创建另一个类。类之间可能有很多公共代码,因为这些类中的一些可能会执行您不能放在父类上的类似事情。

最佳解决方案是创建基本类,这些基本类可以通过注入您希望特定实例具有的行为来轻松修改。例如,要创建一只有机猫和一只机器猫,您只需创建一个Cat并向实例注入所需的行为,以便它采用注入的行为。

从表面上看,这看起来并没有多大改进,因为类的数量只减少了一个。但是,如果再添加一个行为(即WildAnimalBehavior),就不必创建两个动物类了。此外,如果您再添加5个动物,您可以想象这个类层次结构将变得多么复杂。此设计的主要思想是将行为添加到对象,而不是仅仅为了对某些行为建模而创建类。事实上,此设计可以允许创建具有某些混合行为的对象。例如,您无需创建CyborgCat类,而只需将机器人和有机行为注入Cat实例(通过新的CyborgBehavior类)。

public abstract class Animal {
    protected abstract void makeNoise();
    protected abstract void eat();
}
public class Cat extends Animal {
    private Behavior behavior;
    
    public Cat(Behavior behavior) {
        this.behavior = behavior;
    }
    @Override
    public void makeNoise () {
        behavior.makeNoise();
    }
    
    @Override
    public void eat () {
        behavior.eat();
    }
}
public interface Behavior {
    void makeNoise();
    void eat();
}
public class OrganicBehavior implements Behavior {
    
    @Override
    public void makeNoise () {
        System.out.println(this.getClass().getSimpleName() + ": I am an organic being. I make a natural sound!");
    }
    
    @Override
    public void eat () {
        System.out.println(this.getClass().getSimpleName() + ": Thank you! I require nourishment to live.");
    }
}
public class RoboticBehavior implements Behavior {
    
    @Override
    public void makeNoise () {
        System.out.println(this.getClass().getSimpleName() + ": beep beep... dit dot beep..");
    }
    
    @Override
    public void eat () {
        System.out.println(this.getClass().getSimpleName() + ": I do not require food.");
    }   
}
public class DependencyInjectionDemo {
    
    public static void main (String[] args) {
        Cat roboticCat = new Cat(new RoboticBehavior());
        Cat organicCat = new Cat(new OrganicBehavior());
        
        roboticCat.makeNoise();
        roboticCat.eat();
        organicCat.makeNoise();
        organicCat.eat();
    }
}

输出:

RoboticBehavior: beep beep... dit dot beep..
RoboticBehavior: I do not require food.
OrganicBehavior: I am an organic being. I make a natural sound!
OrganicBehavior: Thank you! I require nourishment to live.

虽然我使用了这个示例(基于您的原始模型),但使用DI的更好方法是为每个方法或方法系列创建行为(方法是对象的行为)。例如,EatingBehaviorNoiseBehavior等。这样,您可以更好地混合和匹配行为。例如,可以创建Cat的两个实例来显示机器人行为。然而,也许有一个更先进的例子,它能够发出有机猫的噪音,而不是基本的机器人噪音,而且仍然不像其他机器猫那样需要食物。分离该问题中的行为将允许您对代码进行此类调整,而无需创建另一个类来显示此类混合行为。

我希望您会发现这个示例很有用。顺便说一句,这就是战略模式。您应该在Web上搜索该主题以及依赖项注入以了解更多信息。在现实世界的应用程序中,我想像《顶点传奇》、《天际迷航》和《使命召唤》等游戏都会使用这种设计模式,将皮肤应用到基本角色上。在Skyrim中,当创建角色时,角色包含一些基本属性。当您正在创建角色或设计角色时,属性会随着您为角色选择(注入)新属性(如肤色、疤痕、嘴型等)而改变。当您选择皮肤时,其他游戏也是如此。

相关文章