C# Design – Enforcing Behavior Coupling in Interface Methods

cdesigninterfaces

Many times I want to define an interface with some methods that maintain a behavior relationship between them.

However, I feel that many times this relationship is implicit. With that in mind, I asked myself: Is there any way to enforce a behavior relationship between interface methods?

I thought about defining this behavior via inheritance (by defining a common implementation). But since C# does not allow multiple inheritance, I believe that many times an interface would be more advisable and that inheritance is not flexible enough.


For example:

public interface IComponent
{
    void Enable();
    void Disable();
    bool IsEnabled();
}

For this interface, I wanted the following relationship to be fulfilled:

  • If Enable() is called, IsEnabled() should return true.
  • If Disable() is called, IsEnabled() should return false.

In that example, the behavior constraint that I would want to enforce is:

  • When implementing Enable(), the implementer should ensure that IsEnabled() returns true
  • When implementing Disable(), the implementer should ensure that IsEnabled() returns false

Is there a way to enforce this implementation constraint? Or, the fact that I am thinking about enforcing this kind of constraint is itself a sign that there is a flaw in the design?

Best Answer

Well, first of all, let's tweak your interface a bit.

public interface IComponent
{
    void Enable();
    void Disable();
    bool IsEnabled { get; }
}

Now then. What could potentially go wrong here? For example, could an exception be thrown in the Enable() or Disable() methods? What state would IsEnabled be in then?

Even if you use Code Contracts, I don't see how IsEnabled can be correlated to the use of your Enable or Disable methods unless those methods are guaranteed to succeed. IsEnabled should represent the actual state your object is in, not some hypothetical state.


That said, all you really need is

public interface IComponent
{
    bool IsEnabled { get; set; }
}

Clear it, and the component disables itself.