1

There is something I do not understand about open-close principle. Let's say that you have done this code:

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

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

This code works perfectly, you've done a first release, eveyrthing is OK.
Now you want to add some features, like a player can equip a ring. Open-close principle says open to extension, close to modification. How could I implement the fact that my players can have rings if I shouldn't modify these class?

Maxime Recuerda
  • 476
  • 3
  • 14
  • You could consider reading [this nice answer](https://stackoverflow.com/a/48654003/2846483). – dymanoid Oct 15 '18 at 09:49
  • 2
    That's an extension not a modification at all you are extending the player class to have a ring which will be inherited by default by each child. modification for example is to add an abstract method that shall be implemented by each child which is a modification. – Michel Hanna Oct 15 '18 at 09:50

2 Answers2

2

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.

FCin
  • 3,804
  • 4
  • 20
  • 49
2

You can modify class Player by adding new methods and fields. It is open to extension. But if you already have some methods like Jump or Fight and you want to modify them - that is breaking the principle.

Imagine, your class Fighter has method Fight() and it uses only bare hands:

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

If you want Fighter to fight with a stick (for example) you should not modify initial method Fight() but add another class like FighterWithStick : Fighter and override method Fight() there:

public FighterWithStick() : Fighter
{
  ...
  public override void Fight()
  {
    //use stick
  }
}
xneg
  • 1,204
  • 15
  • 24