我在我的第一个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");
}
}
}
答案 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;。