我需要更改哪些内容才能正确实施 SOLID 设计?
Posted
技术标签:
【中文标题】我需要更改哪些内容才能正确实施 SOLID 设计?【英文标题】:What do I need to change to implement SOLID design correctly? 【发布时间】: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
很可能需要一些升级来应对
【参考方案1】:
Liskov 替换原则 通常与您如何定义类有关。如果您编写一个派生自其他类(或实现某个接口)的类,则想法是有人应该能够使用您的类,就好像它是该父类的实例一样。您的子类可能具有父类没有的其他行为(当然,将您的类当作父类的实例使用的人将无法访问它),但是所有行为父类在子类中应该保持原样。
在您的示例中,这可能意味着定义不适合 Slot
的 MagicalWholeBodyArmor
,因此如果您尝试访问其 Slot
属性,则会引发异常。将MagicalWholeBodyArmor
视为IArmor
的人在尝试查看它适合哪个插槽时会大吃一惊。
您编写的代码确实违反了 SOLID 规则,即 开放/封闭原则。 Open/Closed 原则的一个很好的经验法则是“如果我更改这段代码,我还必须更改其他地方的多少其他代码位?”。如果答案是“很多”,那可能是因为您违反了开放/封闭原则。
在您的情况下,添加一个新的 EquipmentType
枚举成员意味着您必须在 Player
类中找到该 switch 语句并添加一个新的情况。
如果只有一个 switch 语句,那还不错。如果您添加了一种新型设备,那么您的Player
类可能需要升级无论如何,因此修改 switch 语句作为其中的一部分是可以的。尝试以自己的方式解决这个问题将意味着大量的抽象,而收益却很少。
但是,如果您在许多不同的地方有很多很多 switch 语句,它们都在查看 EquipmentType
,(并根据它做出不同的决定),那么您需要找到它们并全部修复它们,那么这就更严重地违反了开放/封闭原则,这可能表明您需要重新架构事物以将所有这些独立的、不同的逻辑位集中到一个地方。
【讨论】:
以上是关于我需要更改哪些内容才能正确实施 SOLID 设计?的主要内容,如果未能解决你的问题,请参考以下文章
我需要更改哪些内容才能从 SEDE 获取已删除、锁定的帖子的计数?
此 package.json 文件需要更改哪些内容才能使用 npm 0.3.0?
必须在客户端或服务器端更改哪些内容才能使 getJSON() 工作?