方法中的多个泛型

问题描述 投票:3回答:2

我的主要问题是,如果将通用对象扩展例如,可以将两个对象绑定两种类型。 4种。没有一个例子,我真的不知道如何问这个问题。

因此,我创建了一个简单游戏的小例子,其中勇士或游骑兵可以装备不同类型的武器(单手,双手,近战,远程)。每个武器都有两个属性。因此,例如武器类型Dagger extends Weapon implements OneHanded, Melee

游侠等级(可以使用双手远程武器):

    private Weapon weapon;

    public <T extends TwoHanded & Ranged> void equip(T weapon) {
        this.weapon = (Weapon) weapon;
    }

战士阶层(可以使用单手,两手,近战,远程武器:]

    private Weapon weapon;
    public <T extends OneHanded & Melee & Ranged> void equip(T weapon) { //probably have to do this differently
            this.weapon = (Weapon) weapon;
    }

弓箭手职业:

public class Bow extends Weapon implements TwoHanded, Ranged {}
public class Dagger extends Weapon implements OneHanded, Melee {}

public void equipTest() {
    ranger.equip(bow);    //works fine
    warrior.equip(dagger); //does not work
}

这里的主要问题是(我认为)我不知道如何实现,战士可以为不同的武器装备不同的属性(例如弓(远距,双手)或匕首(近战,单手) ),而护林员只有一种可能性。如何解决此问题?

java generics inheritance multiple-inheritance type-parameter
2个回答
2
投票

由于Dagger未实现Ranged,所以代码未编译。

我认为您的意思是MeleeRanged。这可以写为重载。

<T extends Melee & OneHanded> void equip(T weapon) {
<T extends Ranged & OneHanded> void equip(T weapon) {

注意顺序的更改,以使过载具有明显的擦除效果。但是,最好使用不同名称而不是重载

(此外,我将使用一个间接层,而不是使用基本类型丢失类型信息。]


0
投票

另一个答案直接解决了问题中的问题。如您所见,使用此设计,最适合您的选择是使用一堆equipXXX()方法。

一种替代方法是使用decorator pattern

创建摘要WeaponWeaponDecorator,以便为以后添加新武器类型提供最大的灵活性。

public abstract class Weapon {
...
}

public abstract class WeaponDecorator extends Weapon {
    Weapon _weapon;
    WeaponDecorator(Weapon weapon) {this._weapon = weapon;}
}

转换各种武器类型以充当武器装饰者:

public class OneHanded extends WeaponDecorator {
    OneHanded(Weapon weapon) {
        super(weapon);
    }
}

public class Melee extends WeaponDecorator {
    Melee(Weapon weapon) {
        super(weapon);
    }
}

并且也从Warrior类中删除所有泛型:

public class Warrior  {
    private Weapon weapon;
    public void equip(Weapon weapon) {
        this.weapon = weapon;
    }
}

现在您可以简单地做:

Weapon w = new OneHanded(new Melee(new Dagger()));
Warrior warrior = new Warrior();
warrior.equip(w);

这里是带有代码和更多说明的full example

编辑

如果选择此解决方案,则还应在运行时解决检查所选英雄的所选武器的有效性的责任。例如,可以将其添加到Rangerequip方法中:

if(weapon.isMelee()) //error (unacceptable)

但是随着规则集变得越来越复杂,您可能希望使用其他模式,例如the command pattern。尽管如此,所有这些都将委派给运行时。这是您获得更大灵活性的代价。当然,您也可以尝试通过创建装饰器的层次结构来获得一些编译时的安全性(类似于java.io库所做的事情)。但是,这会使应用程序过于复杂非常快。

最后,如果只有很少的这种组合类型(TwoHanded + MeleeOneHanded + Ranged等),则可以选择其他答案,并且只需要多一些equip方法并且具有安全性编译时类型检查。

© www.soinside.com 2019 - 2024. All rights reserved.