简体   繁体   English

实例化其子类将取决于用户输入的对象

[英]Instantiating objects whose subclass will depend on user input

Please excuse the silly questions, I'm fairly new to Java and OOP and I'm trying to follow the Design patterns (avoiding ifs, switches, etc) but I'm having a hard time doing so. 请原谅愚蠢的问题,我对Java和OOP还是很陌生,我正在尝试遵循设计模式(避免使用if,switch等),但是这样做很难。

So, I'm building a weapon vendor for a 'game' project of my own. 因此,我正在为自己的“游戏”项目建立武器供应商。 This vendor has a list of objects. 该供应商具有对象列表。 These objects are all different instances of the Weapon Superclass (eg Sword, Spear, Axe, etc). 这些对象都是武器超类的所有不同实例(例如,剑,矛,斧等)。

When a user tries to buy a weapon, the vendor will show the weapon list and the user selects one by inputting its list index. 当用户尝试购买武器时,供应商将显示武器列表,并且用户通过输入其列表索引来选择武器列表。

I'm now facing two problems: 我现在面临两个问题:

1) How can I make an instance of an object whose subclass will depend on user input? 1)如何创建其子类将取决于用户输入的对象的实例? 2) How can I invoke the right constructor, passing the same parameters of the weapon bought to the new object to be instantiated? 2)我如何调用正确的构造函数,将购买的武器的相同参数传递给要实例化的新对象? I'm trying to do this in the most polymorphic way possible, avoiding ifs and switch statements. 我正在尝试以尽可能多态的方式来执行此操作,避免使用ifs和switch语句。

So far, what I tried was making an Interface (iWeapon). 到目前为止,我尝试过制作一个界面(iWeapon)。 Then, based on that interface I made a Factory that receives the type of a weapon (String) and returns a new instance of a weapon with the corresponding subclass. 然后,基于该接口,我创建了一个Factory,该Factory接收武器的类型(字符串)并返回带有相应子类的武器的新实例。

This allowed me to instantiate a 'generic' weapon using the data type of the interface. 这使我可以使用接口的数据类型实例化“通用”武器。 However, I don't know if this is the optimal way of achieving this. 但是,我不知道这是否是实现此目标的最佳方法。 Also, I don't know how to initialize the attributes of the new instance with the same values of the recently bought weapon, in a polymorphic way. 另外,我不知道如何以多态的方式用新购买的武器的相同值来初始化新实例的属性。

I tried creating a method 'getAttributesFromOtherWeapon' on all my weapon subclasses, that receives an object with the same types and simply copies these values. 我尝试在所有武器子类上创建方法“ getAttributesFromOtherWeapon”,该方法接收具有相同类型的对象,并仅复制这些值。 The problem I'm facing now is that the iWeapon type object I instantiate doesn't have this method, and if I include it on the interface I get an error on my subclasses saying that 'Class must either be declared abstract or implement abstract method ' 我现在面临的问题是我实例化的iWeapon类型对象没有此方法,如果我在接口上包含它,我的子类将收到错误消息,指出“类必须声明为抽象或实现抽象方法'

My vendor code does something like this: 我的供应商代码执行以下操作:

Weapon weaponToBuy = (Weapon) weaponList.get(weaponChosenIndex);
iWeapon newWeapon = weaponFactory.getWeapon(weaponToBuy.type);
newWeapon.getAttributesFromOtherWeapon(weaponToBuy);

However, since newWeapon is an iWeapon I needed to declare getAttributesFromOtherWeapon on its interface, which looks like this: 但是,由于newWeapon是iWeapon,因此我需要在其接口上声明getAttributesFromOtherWeapon,如下所示:

public interface iWeapon {


    void getAttributesFromOtherWeapon(iWeapon iWeapon);


}

And now, in every Weapon subclass where I try to implement this method I'm require to pass an iWeapon instead of the corresponding Subclass type (Sword, Spear, etc.). 现在,在我尝试实现此方法的每个Weapon子类中,我都需要传递iWeapon而不是相应的Subclass类型(Sword,Spear等)。 Problem is that in my iWeapon interface I didn't define all the attributes corresponding to a Weapon (or any Weapon subclass) since I understand they'd be defined as constants. 问题是在我的iWeapon界面中,我没有定义与武器(或任何武器子类)相对应的所有属性,因为我知道它们将被定义为常量。

I think there's probably an out of the box solution to this that I'm not seeing due to me being a noob on Java. 我认为可能有一个开箱即用的解决方案,由于我是Java的新手,所以我没有看到。 Any help will be thoroughly appreciated 任何帮助将不胜感激

There are various solutions to this. 有多种解决方案。

1. Use generics 1.使用泛型

interface Weapon<T extends Weapon> {
    public Weapon getAttributesFromOther(T t);
}

class Axe implements Weapon<Axe> {
    @Override
    public Weapon getAttributesFromOther(Axe other) {
        // TODO get those attributes
        return this;
    }
}

... etc. ...等

Pros 优点

Sword#getAtributesFromOther will only take a Sword , if the class is defined as implements Weapon<Sword> . 如果该类定义为implements Weapon<Sword> ,则Sword#getAtributesFromOther仅将使用Sword

Cons 缺点

If by mistake, you declare something like class Dagger implements Weapon<Pitchfork> , then the getAttributes will take a Pitchfork . 如果错误地声明了类似class Dagger implements Weapon<Pitchfork> ,则getAttributes将使用Pitchfork

Negligible in my opinion, as it's all compile-time, but worth considering. 在我看来,这可以忽略不计,因为它全是编译时的,但值得考虑。

Also your weapon references should change to Weapon<?> for unknown weapon types at runtime. 对于运行时未知的武器类型,您的武器引用也应更改为Weapon<?>

2. Declare a WeaponProperties class extending some parametrized Map , and a getter/setter pair in the Weapon interface 2.在Weapon接口中声明一个WeaponProperties类,该类扩展了一些参数化的Map ,以及一个getter / setter对。

Pros 优点

This will work granularily with all weapons, you just have to check whether the property is present. 这将适用于所有武器,只需检查该属性是否存在即可。

You can easily merge properties common to multiple types of weapons. 您可以轻松地合并多种武器共有的属性。

Cons 缺点

Lots of boilerplate in all weapons, lots of "safety" code when copying properties from different weapon types if you allow that. 如果允许的话,从各种武器类型复制属性时,所有武器都有很多样板,有很多“安全”代码。

3. There probably is something even better - will edit if I have an idea 3.有可能一些更好-如果我有一个想法会编辑

Notes 笔记

  • Make sure to follow Java code conventions , eg there's nothing wrong with Hungarian notation, but every type should always be CamelCase (contrary to variable names which are camelBack ). 确保遵循Java代码约定 ,例如,匈牙利表示法没有什么问题,但是每种类型都应始终为CamelCase (与名为camelBack变量名称相反)。 This is about your iWeapon interface, which you can easily just refactor to Weapon - see example above. 这是关于你iWeapon接口,您可以轻松地只是重构为Weapon -见上面的例子。
  • Afterthought: I realized the getAttributes... methods in my example return Weapon , but that's not relevant to this case - you can safely return void instead 事后思考:我意识到示例中的getAttributes...方法返回Weapon ,但这与这种情况无关-您可以安全地返回void

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM