我正在阅读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
中。在对象构造期间,将类型设置为剑或工作人员。但是,这并没有什么帮助,因为你可以创建一个剑对象,传递员工作为类型,然后使用它。
您如何防止将剑添加到向导库存中?
答案 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)
您可以使用泛型:
Weapon
和Staff
类保持不变:
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
方法。