Search code examples
oopdelegatesencapsulationcompositioninformation-hiding

Does the delegate pattern break encapsulation?


Lets say I have a class that takes a delegate:

public class DelegateContainer
{
    private IDelegate delegate;

    public DelegateContainer(IDelegate delegate)
    {
        this.delegate = delegate;
    }

    public void doSomething()
    {
        delegate.doSomethingOnlyForThisPurpose();
    }
{

As you can see the delegate's doSomethingOnlyForThisPurpose() method only exists to be called by the delegating class. However it is required that this method is public and could be executed by anything. If it absolutely shouldn't be executed by anything other than the delegating class it is attached to (especially if the delegating class passes in a dependency) then doesn't this break encapsulation? The only way I have thought to get around this is to contrive an object which can only be instantiated by the delegating class (inner class) which is passed to every method called. However, this is very convoluted and not watertight anyway. Is there any way around this or is it pathological?

Note: I want to stick with this compositional approach so I would rather not resort to inheritance.


Solution

  • It shouldn't break the encapsulation. Your implementation of IDelegate publishes some behaviour that can be invoked by anyone who has a reference to an instance of this so it should be implemented with the required abstraction like any other public behaviour. If you want anyone having an instance, you make public your constructor. If you don't, then you do like you have done (using private or protected constructor).

    The purpose of your IDelegate.doSomethingOnlyForThisPurpose implementation should be to do what it does, regardless of being or not being invoked by the DelegateContainer. I mean, if this method is dangerous if invoked by "wrong hands", then it's tightly coupled to DelegateContainer. In this case it was not the delegation pattern who has broken the encapsulation.

    Just a quick note:

    I don't know what language you're using. In C# you can implement IDelegate.doSomethingOnlyForThisPurpose explicitly to be used by those who are particularly interested in this interface:

    class MyClass: IDelegate
    {
    
        void IDelegate.doSomethingOnlyForThisPurpose() {
    
            // This method is only visible by 
            // who is representing your object as IDelegate.
            // It's not visible by who is representing it as MyClass.
        }
    }
    

    Conclusion: you shouldn't have a non private method called doSomethingOnlyForThisPurpose if "OnlyForThisPurpose" means it's unsafe to be called anytime (you already know this), and you shouldn't want your method being invoked outside your class (by DelegateContainer) if you're "shy" to publish it (that's the bad news). It's a design issue but not a Delegation Pattern pathology.