面向对象设计 - 处理项目和库存

时间:2015-11-10 10:03:52

标签: java oop

我在我的第一个java项目上工作,这是一个基本的角色扮演游戏。我有一个关于处理物品和库存的问题。首先,我概述了一些课程。 Item是一个描述所有项目的抽象类。 Item的子类是Weapon(抽象类)和Armor(非常合理,我将来会有更多的东西)。武器有两个子类 - MelleWeapon和RangedWeapon。这总结了如何按类别处理项目。另外,我有一个Inventory类,它描述了每个角色的库存。

代码有效,但需要一些升级。我至少有两个主要问题:

首先,Item的每个具体子类都有一个getItem方法,它几乎完全相同。我怎样才能避免这种代码欺骗?

其次,库存中的addToInventory方法可以变得更长,因为我向Item添加了更多子类(很多if / elseif),所以我猜它是一个糟糕的设计。如何以优雅的方式避免使用?

abstract public class Item {

private String name;
private long cost;
private double weight;

public Item(String name, double weight, long cost) {
    this.name = name;
    this.weight = weight;
    this.cost = cost;
}

public String getName() { return name; }
public void setName(String name) { this.name = name; }

public double getWeight() { return weight; }
public void setWeight(double weight) { this.weight = weight; }

public long getCost() { return cost; }
public void setCost(long cost) { this.cost = cost; }

}


abstract public class Weapon extends Item{

private boolean oneHanded;
private String reqTraining;
private int n;
private int dice;
private int attackBonus;
private int damageBonus;


Weapon(String name, double weight, long cost, boolean oneHanded, String reqTraining,  int n, int dice, int attackBonus, int damageBonus) {
    super(name, weight, cost);
    this.oneHanded = oneHanded;
    this.reqTraining = reqTraining;
    this.n = n;
    this.dice = dice;
    this.attackBonus = attackBonus;
    this.damageBonus = damageBonus;
}


String getReqTraining(){ return reqTraining; }
int getN() { return n; }
int getDice() { return dice; }
int getAttackBonus() {return attackBonus; }
int getDamageBonus(){ return damageBonus; }

public abstract void attack(Character attacker, Character defender);
}



public class Armor extends Item{

private String reqTraining;
private int acBonus;

Armor(String name, String reqTraining, int acBonus,double weight, long cost) {
    super(name, weight, cost);
    this.reqTraining = reqTraining;
    this.acBonus = acBonus;
}

static List<Armor> armorList = new ArrayList<Armor>();

static
{
    armorList.add(new Armor("Full Plate Armor","Heavy", 8, 25, 200));
    armorList.add(new Armor("Chain Mail Armor","Medium", 5, 18, 120));

}

String getReqTraining(){ return reqTraining; }
int getACBonus() { return acBonus; }


public static Armor getItem(String itemName) {
    try {
        for (Iterator<Armor> iter = armorList.iterator(); iter.hasNext(); ) {
            Armor item = iter.next();
            if (itemName.equals(item.getName())) {
                return item;
            }
        }

    } catch (Exception e) {
        System.out.println(itemName + " haven't been found in spells-list");
        return null;
    }
    return null;
}

}




public class  MeleeWeapon extends Weapon {

boolean throwable;

MeleeWeapon(String name,boolean oneHaned, String reqTraining, int n, int dice, int attackBonus, int damageBonus,double weight, long cost, boolean throwable) {
    super(name, weight, cost, oneHaned, reqTraining, n, dice, attackBonus, damageBonus);
    this.throwable = throwable;
}

static List<MeleeWeapon> meleeWeaponList = new ArrayList<MeleeWeapon>();

static
{
    meleeWeaponList.add(new MeleeWeapon("Long Sword",true, "Martial", 1, 8, 0, 0,8, 10, false));
    meleeWeaponList.add(new MeleeWeapon("Short Sword",true, "Martial", 1, 6, 0, 0,5, 5, false));
    meleeWeaponList.add(new MeleeWeapon("Dagger",true, "Basic", 1, 4, 0, 0,2, 3, true));
    meleeWeaponList.add(new MeleeWeapon("Quarter-staff",false, "Basic", 1, 4, 0, 0,3, 2, false));
    meleeWeaponList.add(new MeleeWeapon("Shield",false, "Martial", 1, 4, 0, 0,8, 8, false));

}


public void attack(Character attacker, Character defender){

    int attackRoll = DiceRoller.roll(20) + attacker.getBaseAttackBonus() + attacker.getModifier(attacker.getStrength()) + getAttackBonus() ;
    System.out.println(attacker.getName() + " attack Roll: " + attackRoll + "AC: " + defender.getArmorClass());

    if (attackRoll >= defender.getArmorClass()){
        System.out.println("Defender: " + defender.getName() + " had " + defender.getCurrentHp());
        int damage = DiceRoller.roll(getN(), getDice()) + attacker.getModifier(attacker.getStrength()) + getDamageBonus() ;
        System.out.println("Damage : " + damage);
        defender.setCurrentHp(attacker.getCurrentHp() - damage);
        System.out.println("Defender: " + defender.getName() + " has " + defender.getCurrentHp());
    } else {
        System.out.println("Missed Attack");
    }

}

public static  MeleeWeapon getItem(String itemName) {
    try {
        for (Iterator<MeleeWeapon> iter = meleeWeaponList.iterator(); iter.hasNext(); ) {
            MeleeWeapon item = iter.next();
            if (itemName.equals(item.getName())) {
                return item;
            }
        }

    } catch (Exception e){
        System.out.println(itemName + " haven't been found");
        return null;
    }
    return null;
}


}




public class RangedWeapon extends Weapon {

private String shoots;

RangedWeapon(String name, boolean oneHaned, String reqTraining, String shoots, int n, int dice, int attackBonus, int damageBonus, double weight, long cost) {
    super(name, weight, cost, oneHaned, reqTraining, n, dice, attackBonus, damageBonus);
    this.shoots = shoots;
}


static List<RangedWeapon> rangedWeaponList = new ArrayList<RangedWeapon>();

static {
    rangedWeaponList.add(new RangedWeapon("Long Bow", false, "Archery", "Arrow", 1, 8, 0, 0, 5, 10));
    rangedWeaponList.add(new RangedWeapon("Short Bow", false, "Archery", "Arrow", 1, 6, 0, 0, 3, 5));
}


public void attack(Character attacker, Character defender) {

    int attackRoll = DiceRoller.roll(20) + attacker.getBaseAttackBonus() + attacker.getModifier(attacker.getDexterity()) + getAttackBonus();
    System.out.println(attacker.getName() + " attack Roll: " + attackRoll + "AC: " + defender.getArmorClass());

    if (attackRoll >= defender.getArmorClass()) {
        System.out.println("Defender: " + defender.getName() + " had " + defender.getCurrentHp());
        int damage = DiceRoller.roll(getN(), getDice()) + attacker.getModifier(attacker.getStrength());
        System.out.println("Damage : " + damage);
        defender.setCurrentHp(attacker.getCurrentHp() - damage);
        System.out.println("Defender: " + defender.getName() + " has " + defender.getCurrentHp());
    } else {
        System.out.println("Missed Attack");
    }

}

public static RangedWeapon getItem(String itemName) {
    try {
        for (Iterator<RangedWeapon> iter = rangedWeaponList.iterator(); iter.hasNext(); ) {
            RangedWeapon item = iter.next();
            if (itemName.equals(item.getName())) {
                return item;
            }
        }

    } catch (Exception e) {
        System.out.println(itemName + " haven't been found");
        return null;
    }
    return null;
}

}



public class Inventory {

private Map<String,Item> inventory;

Inventory() {

    inventory = new HashMap<String, Item>();
}


public void showInventory() {

    System.out.println("Show Inventory: ");

    for (Map.Entry<String,Item> entry: inventory.entrySet()) {
        System.out.println(entry.getKey());
        }

    System.out.println(" ");
}


public void addToInventory(String itemName) {

    Item newItem = null;

    try {

        if (MeleeWeapon.getItem(itemName) != null) {
            newItem = MeleeWeapon.getItem(itemName);
        } else if (RangedWeapon.getItem(itemName) != null) {
            newItem = RangedWeapon.getItem(itemName);
        } else if (Armor.getItem(itemName) != null) {
            newItem = Armor.getItem(itemName);
        }else
            System.out.println("Add futural other options (like potions) ");

            System.out.println(newItem.getName() + " has been added to inventory");
            inventory.put(newItem.getName(), newItem);

    } catch (Exception e){
        System.out.println("Adding " + itemName +"to inventory has failed");
    }

}

}

2 个答案:

答案 0 :(得分:1)

问题在于您使用字符串来识别程序中的对象,这是一种常见的反模式,也是错误和性能问题的重要来源。

如果你用简单的字符串识别东西,你会遇到这样的问题:(a)当你使用它时,名字中可能会有拼写错误;(b)你必须一直查看这些东西。

您应该使用Java标识符来识别事物。通常的方法是使用public static final。例如:

public static final Armor FULL_PLATE_ARMOR = new Armor("Full Plate Armor","Heavy", 8, 25, 200)

然后,您可以在代码中使用此标识符,如果您需要GUI中的选择列表,则可以将其添加到数组中。

然后,您可以删除getItem方法。

答案 1 :(得分:0)

不完全是解决方案,但有两个提示:

  • 你的getItem()效率不高。考虑使用Set结构来存储数据,然后访问是O(1)。在任何情况下,如果您使用&#34; new&#34;则不需要迭代器。那种循环。

  • 考虑使用泛型,这可能会减少你的双重实现&#34;。