【发布时间】:2019-10-20 11:09:02
【问题描述】:
我正在尝试学习 SOLID 设计,但我认为我犯了一个错误。我认为IItem 接口在我的Player 类中不遵循Liskov 替换原则,但是我不知道如何解决这个问题。如果我从 IItem 添加一个新的界面绘图,我将不得不更改 Player 的方法以添加一个案例来处理它。
我希望 Player 类只需要一种装备方法,因此需要帮助了解我做错了什么以及如何正确做。
我的界面的简化版:
interface IItem
{
string Name { get; set; }
int Value { get; set; }
Quality Quality { get; set; }
EquipmentType Type { get; set; }
}
interface IWeapon : IItem
{
}
interface IArmour : IItem
{
int Defence { get; set; }
Slot Slot { get; set; }
}
消费类 Player 类:
class Player
{
private Dictionary<Slot, IArmour> armour = new Dictionary<Slot, IArmour>();
private IWeapon weapon;
public bool Equip(IItem item)
{
switch (item.Type)
{
case EquipmentType.Armour:
var armour = item as IArmour;
if (this.armour.ContainsKey(armour.Slot))
{
return false;
}
this.armour.Add(armour.Slot, armour);
return true;
case EquipmentType.Weapon:
var weapon = item as IWeapon;
throw new NotImplementedException();
default:
return false;
}
}
}
上下文枚举:
enum Slot
{
Head = 0,
Soulders = 1,
Gloves = 2,
Neck = 3,
RRing = 4,
LRing = 5,
Torso = 6,
Legs = 7,
Boots = 8,
Bracers = 9,
Belt = 10,
}
enum EquipmentType
{
Armour = 0,
Weapon = 1
}
【问题讨论】:
-
是什么让你认为你在这里破坏了 LSP?
-
@canton7 如果我以后从 IItem 添加一个新的派生接口,我将不得不更改播放器,据我了解这意味着它是不可替代的?
-
这里看起来更像是打开/关闭违规(SOLID 的“O”),而不是 Liskov 替换问题。如果您需要进行更改,则意味着您的代码没有关闭进行修改。
-
@Corentin Pane,好点子!你能给我什么建议让我回到正轨吗?我还在努力学习:)
-
如果你有一个派生自例如的类,你会破坏 LSP。
IArmor(我们称它为Shield),如果您使用IArmor引用它,则该类的行为与使用Shield引用它时的行为不同。如果有的话,这违反了打开/关闭原则,因为如果您添加另一种类型的设备,您需要修改您的Player类以正确处理它(以及使用EquipmentType的所有其他地方)。但是我不会在这里担心 - 如果您添加一种新型设备,您的Player很可能需要一些升级来应对