Open closed principle, refactoring

I'm trying to apply OCP to a piece of code that I have that the current state is really smelly in it, but I feel like I'm not getting to the end.

Current code:

public abstract class SomeObject
{}

public class SpecificObject1 : SomeObject
{}

public class SpecificObject2 : SomeObject
{}


// Smelly code
public class Model
{
  public void Store(SomeObject someObject)
  {
    if (someObject is SpecificObject1)
    {}
    else if (someObject is SpecificObject2)
    {}
  }
}

      

This is really ugly, my new approach looks like this:

// No so smelly code
public class Model
{
  public void Store(SomeObject someObject)
  {
    throw new Expception("Not allowed!");
  }

  public void Store(SpecificObject1 someObject)
  {}

  public void Store(SpecificObject2 someObject)
  {}

}

      

When a new type SomeObject appears, I have to implement how that particular object is, it will violate OCP because I need to change the model class.

To move store logic to SomeObject also feels like the wrong reason, I will be breaking SRP (?) Because in this case SomeObject is almost like a DTO, it is incompatible with not knowing to store itself.

If there is a new implementation of SomeObject that has no implementation implementation I get a runtime error due to an exception in the Store method in the Model class, it also looks like a code smell.

This is because the calling code will be in the form

IEnumerable<SomeObject> sequence;

      

I won't know the specific types of sequence objects.

I cannot understand the concept of OCP. Does anyone have specific examples or links that are a little more than some Car / Fruit examples?

+2


a source to share


1 answer


The sample I present allows you to register handlers for specific objects. There should be a registerd handler for every type of object that can happen. If the handler cannot handle this, an exception is thrown.

You can load handlers (whatever implements IHandler

) dynamically from yours or from other assemblies, and instantiate and add them.
Therefore, it is sufficient to create a handler class for any type that implements SomeObject

.



public interface IHandler {
    bool TryHandle (SomeObject o); // return true iff handled
}

public class Model
{
    private List<SIandler> _Handlers = new List<IHandlers>();

    // registers a new handler
    public void RegisterHandler (IHandler h) {
        _Handlers.Add(h);
    }

    // this tries to store an object by letting all handlers attempts to store
    public void Store (SomeObject o) {
        foreach (var h in _Handlers) {
            if (h.Store(o)) return;
        }

        // no handler was able to handle the type
        throw new Exception();
    }
}

public class Specific1Handler: IHandler
{
    public bool Handle (SomeObject o) {
        if (o is SpecificType1) {
            /* store... */
            return true; // we handled this object
        } else {
            // we're not qualified
            return false;
        }
    }
}

      

I believe this would suit your needs. (By the way, I don't know if this template has a name, it would be nice to know if it does.)

+1


a source







All Articles