防止将某些对象添加到ArrayList

时间:2017-10-04 00:58:34

标签: java oop arraylist

我正在阅读Eric Lippert关于Wizards and Warriors的博客。有趣的阅​​读,但我发现某些部分难以理解(不是作者的错,我只是OOP的初学者)。

他在游戏,向导和战士中提出了两种角色类型的问题,规则是:

  • 战士只能使用剑。
  • 向导只能使用员工

在博客中,他在第一部分使用getter / setter来处理角色的武器,但让我们将其更改为库存系统。因此,我们有一个abstract class名为Player的项目列表(ArrayList)。

interface Weapon {
  attack(Enemy enemy);
}

public class Staff implements Weapon {} 

public abstract class Player {
    private List<Weapon> weaponInventory;

    //left out constructor and other methods to keep it on point

    abstract void add(Weapon add)
}

并像这样使用它:

public class Wizard extends Player {

   @Override
   public void add(Weapon add){
      //code to add weapon;
   }
}

如何构建add方法以强制执行向导只能使用人员的规则?我想在武器上调用getClass()getType()但这些被认为是不好的做法。

我能想出的最佳答案是String变量名为type,而getter位于Weapon interface中。在对象构造期间,将类型设置为剑或工作人员。但是,这并没有什么帮助,因为你可以创建一个剑对象,传递员工作为类型,然后使用它。

您如何防止将剑添加到向导库存中?

3 个答案:

答案 0 :(得分:2)

  

如何构建add方法以强制执行向导只能使用人员的规则?

要么你没有阅读整个系列,要么你不理解它的核心信息。该系列文章的重点是表达没有好的方法来构建一个强制限制子类之间关系的方法

这只是关于基于子类的OOP的一个事实;有些东西不能很好地塑造,这就是其中之一。许多OOP类型系统的基本原理,包括Java和C#,是Liskov的:你可以总是使用需要超类实例的子类实例。这使得类型系统中的建模限制变得困难。

在本系列的最后一部分中,我提供了我所知道的最佳解决方案:将模拟规则模型化为对象本身,并有一个规则强制类,在用户提供反馈时企图违反规则。不要让类型系统试图解决您的业务问题。

答案 1 :(得分:1)

您可以使用以下内容。注意:在Player类中,武器可以是任何类型。但是,每个玩家子类都有自己的特定add()。因此,虽然这种方法强制执行所需的规则,但它会失去一点普遍性。

public class Staff implements Weapon {} 
public class Sword implements Weapon {} 

public abstract class Player {
    private List<Weapon> weaponInventory;
    protected final void addWeapon(Weapon weapon) {
         weaponInventory.add(weapon)
    }
 }

 public class Wizard extends Player {
     public void add(Staff staff) {
         addWeapon(staff);
     }
 }

 public class Warrior extends Player {
     public void add(Sword sword) {
         addWeapon(sword);
     }
 }

答案 2 :(得分:0)

您可以使用泛型

WeaponStaff类保持不变:

public interface Weapon {
   void attack(Enemy enemy);
}

public class Staff implements Weapon {

   @Override
   public void attack(Enemy enemy) {
    //Do ur attacking. :)
   }

}

Player类的泛型类型

import java.util.ArrayList;
import java.util.List;

public abstract class Player<T extends Weapon> {
    protected List<T> weaponInventory = new ArrayList<>();//Made protected so Wizard can access it.

    public abstract void add(T weapon);

}

Wizard课程延伸Player<Staff>(不只是Player):

public class Wizard extends Player<Staff> {

    @Override
    public void add(Staff weapon) {
        // Add the staff to the list declared in Player
        weaponInventory.add(weapon);
    }

}

说明:

T中的Player<T>是您希望玩家使用的武器类型。

当您在Player<Staff>课程中展开Wizard时,您表示希望Wizard成为仅使用Player的{​​{1}}秒。这样,Staff的{​​{1}}列表将仅包含Wizard个。

当您添加weaponInventory类时,它会扩展Staff,这会使其Warrior只接受Player<Sword>

顺便说一下,我在上面的代码中实例化了weaponInventory,并在Sword中实现了weaponInventory方法。