关于新特性的开闭原则

Open-Close principle about new features

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

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

public sealed class Fighter : Player { /* ... */ }
public sealed class Warrior : Player { /* ... */ }

此代码完美运行,您已完成第一个版本,一切正常。
现在您想添加一些功能,例如玩家可以装备戒指。开闭原则说对扩展开放,对修改关闭。如果我不应该修改这些 class?

,我怎么能实现我的球员可以拥有戒指的事实

First think why this kind of rule might be useful. Closed to modification, open to extension. This makes sense for libraries or code that must be backwards compatible. Think of this example:

I've written "BestLibrary" library which exposes interface:

namespace BestLibrary
{
    public interface GoodStuff
    {
         Goodies GiveMeGoodStuff();
    }
}

But in the next release I want to decide what Goodies to give based on a parameter, so I change the interface to:

namespace BestLibrary
{
    public interface GoodStuff
    {
         Goodies GiveMeGoodStuff(GoodiesType type);
    }
}
public enum GoodiesType { All, Type1, Type2 }

Now everyone who uses my library has to fix their code, because their projects will stop building. This brakes Open/Closed principle. Instead I should make another method, like this:

namespace BestLibrary
{
    public interface GoodStuff
    {
         Goodies GiveMeGoodStuff();
         Goodies GiveMeGoodStuff(GoodiesType type);
    }
}

Here I didn't modify anything. Old code still works. Someone wants random Goodies? They can still get it. I extended GoodStuff interface with additional method. This way everything compiles and people can use new functionality.

If you work on a project that is not a library or api, then I don't see any reason to follow this principle. Requirements change and code should follow.

可以通过添加新方法和字段来修改class Player。它对扩展开放。但是如果你已经有了一些像 JumpFight 这样的方法并且你想修改它们 - 那是违反原则的。

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

public Fighter() : Player
{
  ...
  public virtual void Fight()
  {
    //use bare hands
  }
}

如果你想要Fighter用棍子打架(例如)你不应该修改初始方法Fight()而是添加另一个class像FighterWithStick : Fighter并覆盖方法Fight() 那里:

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