【发布时间】:2020-02-14 04:08:58
【问题描述】:
C# 7.1 中引入了一个新功能,称为通用模式匹配。我发现的其中一个示例如下所示:
void Attack(IWeapon weapon, IEnemy enemy)
{
switch (weapon)
{
case Sword sword:
// process sword attack
break;
case Bow bow:
// process bow attack
break;
}
}
但在我看来,这是一个不正确的设计,违反了第二个 SOLID 原则(开闭)。我什至无法想到可能需要这样做的情况,根据我的理解,如果您遇到需要这种开关的情况,那么您做错了什么。另一方面,如果将此功能添加到语言中,则必须有充分的理由这样做。所以问题是——假设你没有创建糟糕的架构,你什么时候需要这个。
【问题讨论】:
-
它违反了它,它强制您编辑代码以支持额外类型的
IWeapon(代码未关闭以供修改)。 -
@KorsaR 这与 OCP 无关,也不违反 OCP。具体的武器类没有被修改——事实上,每次你想要编写一个新的基于类型的函数时,它们不必被修改。是的,添加模式匹配和其他功能特性有 非常 充分的理由。它们减少脆弱性,它们不强迫您修改
Weapon,它们允许您编写编译器本身可以验证是否正常工作的代码。没有它,您将不得不依赖运行时验证和强制转换来获得正确的武器类型 -
我不能同意,要添加新类型您必须修改代码,
IWeapon只是一个字谜,方法相反,它应该在IWeapon上。但是针对具体类型检查IWeapon直接违反了OCP。您不能在不修改代码的情况下将任何新类型的IWeapon添加到代码中,从而使IWeapon无用。至少如果它检查ISwingableObject或IShootableObject我会同意它在某种程度上符合 OCP,即使设计很差。 -
OCP 背后的想法是,您可以拥有多个具有相同操作的对象,并且您不必受限于必须实现要对其执行操作的确切具体类型。也就是说,你不需要教它剑/矛/刀,你只需要教它操作,即
ISwingableWeapon。如果您想添加新操作,那么是的,您必须编写新代码(显然)。但是,如果您要重用相同的操作,例如在经典的 Rectangle/Circle OCP 解释中使用 CalculateArea(),那么您可以通过使用接口而不是具体类型来使其成为 OCP。 -
推测是在您的
IronFist类中定义的。case ISwingableWeapon weapon: weapon.Swing();。铁拳级可以处理它。然后你可以添加任何可摆动的武器,比如ChairLeg,而且你永远不必改变你的职业。
标签: c# switch-statement c#-7.1