C# 关于新特性的开闭原理

C# 关于新特性的开闭原理,c#,solid-principles,open-closed-principle,C#,Solid Principles,Open Closed Principle,关于开闭原则,我有点不明白。假设您已经完成了以下代码: public abstract class Player { public string Name { get; set; } public int Level { get; set; } } public sealed class Fighter : Player { /* ... */ } public sealed class Warrior : Player { /* ... */ } 这段代码工作得很好,您已经

关于开闭原则,我有点不明白。假设您已经完成了以下代码:

public abstract class Player
{
    public string Name { get; set; }
    public int Level { get; set; }
}

public sealed class Fighter : Player { /* ... */ }
public sealed class Warrior : Player { /* ... */ }
这段代码工作得很好,您已经完成了第一个版本,一切都正常。

现在你想添加一些功能,比如玩家可以装备戒指。开-关原则是“开-扩,关-改”。如果我不修改这些类,我如何实现我的玩家可以拥有戒指的事实呢?

首先想想为什么这种规则可能有用。关闭修改,打开扩展。这对于必须向后兼容的库或代码是有意义的。想想这个例子:

我编写了“BestLibrary”库,它公开了接口:

namespace BestLibrary
{
    public interface GoodStuff
    {
         Goodies GiveMeGoodStuff();
    }
}
但是在下一个版本中,我想根据一个参数来决定要提供什么
Goodies
,因此我将界面更改为:

namespace BestLibrary
{
    public interface GoodStuff
    {
         Goodies GiveMeGoodStuff(GoodiesType type);
    }
}
public enum GoodiesType { All, Type1, Type2 }
现在每个使用我的库的人都必须修复他们的代码,因为他们的项目将停止构建。这是制动器打开/关闭的原理。相反,我应该提出另一种方法,如下所示:

namespace BestLibrary
{
    public interface GoodStuff
    {
         Goodies GiveMeGoodStuff();
         Goodies GiveMeGoodStuff(GoodiesType type);
    }
}
在这里,我没有修改任何内容。旧代码仍然有效。有人想要随机的
糖果
?他们仍然可以得到它。我用额外的方法扩展了
GoodStuff
接口。这样,一切都可以编译,人们可以使用新的功能


如果您从事的项目不是库或api,那么我看不出有任何理由遵循这一原则。需求变化,代码也应该随之变化。

首先想想为什么这种规则可能有用。关闭修改,打开扩展。这对于必须向后兼容的库或代码是有意义的。想想这个例子:

我编写了“BestLibrary”库,它公开了接口:

namespace BestLibrary
{
    public interface GoodStuff
    {
         Goodies GiveMeGoodStuff();
    }
}
但是在下一个版本中,我想根据一个参数来决定要提供什么
Goodies
,因此我将界面更改为:

namespace BestLibrary
{
    public interface GoodStuff
    {
         Goodies GiveMeGoodStuff(GoodiesType type);
    }
}
public enum GoodiesType { All, Type1, Type2 }
现在每个使用我的库的人都必须修复他们的代码,因为他们的项目将停止构建。这是制动器打开/关闭的原理。相反,我应该提出另一种方法,如下所示:

namespace BestLibrary
{
    public interface GoodStuff
    {
         Goodies GiveMeGoodStuff();
         Goodies GiveMeGoodStuff(GoodiesType type);
    }
}
在这里,我没有修改任何内容。旧代码仍然有效。有人想要随机的
糖果
?他们仍然可以得到它。我用额外的方法扩展了
GoodStuff
接口。这样,一切都可以编译,人们可以使用新的功能

如果您从事的项目不是库或api,那么我看不出有任何理由遵循这一原则。需求会发生变化,代码也会随之变化。

您可以通过添加新的方法和字段来修改类
Player
。它可以扩展。但是如果你已经有了一些方法,比如
Jump
Fight
,你想修改它们,那就违反了原则

想象一下,您的类
Fighter
具有方法
Fight()
,并且只使用徒手:

public Fighter() : Player
{
  ...
  public virtual void Fight()
  {
    //use bare hands
  }
}
如果您想使用棍子战斗(例如),您不应该修改初始方法
fight()
,而是添加另一个类,如
FighterWithStick:Fighter
,并覆盖方法
fight()

public FighterWithStick() : Fighter
{
  ...
  public override void Fight()
  {
    //use stick
  }
}
您可以通过添加新方法和字段来修改class
Player
。它可以扩展。但是如果你已经有了一些方法,比如
Jump
Fight
,你想修改它们,那就违反了原则

想象一下,您的类
Fighter
具有方法
Fight()
,并且只使用徒手:

public Fighter() : Player
{
  ...
  public virtual void Fight()
  {
    //use bare hands
  }
}
如果您想使用棍子战斗(例如),您不应该修改初始方法
fight()
,而是添加另一个类,如
FighterWithStick:Fighter
,并覆盖方法
fight()

public FighterWithStick() : Fighter
{
  ...
  public override void Fight()
  {
    //use stick
  }
}

你可以考虑阅读。这是一个扩展,而不是一个修改,你把播放器类扩展成一个每个孩子默认继承的环。例如,修改是添加一个抽象的方法,每个孩子都应该修改它。你可以考虑阅读。这是一个扩展,而不是一个修改。例如,修改是添加一个抽象方法,该方法应由每个子级实现,这是一个修改。