Designing your way out of the CanHandle-Handle conundrum

CanHandle – Handle pattern conundrum

When you have multiple classes implementing an IWorker interface with a CanHandle and Handle method, such as

interface IWorker
{
    public Boolean CanHandle(IWork work);
    public void Handle(IWork work);
}

you find yourself in a conundrum: should you call CanHandle again from Handle?

If you don’t, someone could pass in work that a worker isn’t designed to handle and that can lead to a multitude of different exceptions or subtle, very hard to debug errors. Avoiding those errors was a vote in favor of calling CanHandle from Handle, while the double execution of CanHandle for well behaved clients of your IWorkers was a vote against it.

A previous post – Act like a pessimist and call CanHandle from Handle (again)? – discussed a way out of the conundrum by putting the CanHandle call in an Debug.Assert statement.

That’s a perfectly valid approach. But… what if you could avoid the conundrum altogether?

Avoiding the conundrum

The problem with a class with one method that validates X, and another method then processes X is that you make that class hugely dependent on its clients and you need to take steps to ensure that people use your class the way it was intended to be used.

Why not make it simpler for everyone involved? Simpler for clients of your workers and simpler for your worker classes themselves.

What is the reason for having a CanHandle method to begin with?

The answer usually is that anyone with work to be done can now find a worker that says “yay, I can handle this” and then pass off the work to that worker.

So a client of your workers (usually a work distributor of some sort) would execute a loop like:

    ICollection<IWorker> _Workers;

    public void Distribute(IWork work)
    {
        foreach (var worker in _Workers)
        {
            if (worker.CanHandle(work))
            {
                worker.Handle(work);
                break; 
            }   
        }
    }

But why make a client of your workers pose the question at all? After all, anyone with work looking for a worker to do it, really is only interested in getting their work done.

So … why not simply have them pass the work to the Handle method directly? All you then need to do is make Handle itself check whether it can actually Handle the work and respond accordingly.

    public Boolean Handle(IWork work);

Using this approach the loop in a work distributor would look like:

    public void Distribute(IWork work)
    {
        foreach (var worker in _Workers)
        {
            if (worker.Handle(work))
                break;
        }
    }

Good. And you can make it even better.

Polishing the alternative

Previously, Handle would try to execute the work that it received and only fail to do see as a result of errors or exceptions. Now though, when you call Handle you need to check whether the work was actually accepted for execution. That makes Handle a bit of a misnomer. Accept sounds better.

Another peeve with the above method is that a Boolean result isn’t very descriptive. What does it mean when the method returns false? Was the work not accepted, or was it accepted and was the execution of that work unsuccessful? Personally, I nowadays only use Boolean result values for methods answering a CanXxx, IsXxx, DidXxx, HasXxxx question. In other cases, I prefer a bit more self-documentation and use descriptive enums for parameter and result types. Even if those enums only contain two members.

In this case for example:

    enum AcceptWorkResponse
    {
        Rejected,
        Accepted
    }

This type of return value makes it clear that the work can be rejected. It also conveys that the work has, so far, only been accepted and may not necessarily have been done yet. For example when the work will be executed in a separate thread.

Your Handle, now named Accept, method then is declared as:

    public AcceptWorkResponse Accept(IWork work);

And the loop becomes:

    public void Distribute(IWork work)
    {
        foreach (var worker in _Workers)
        {
            if (worker.Accept(work) == AcceptWorkResponse.Accepted)
                break;
        }
    }

Yes! Much more self-documenting.

Final touch

As the Accept method is now itself telling clients of the IWorker interface whether the work will be done, there is no need to keep CanHandle around. Doing so would only serve to confuse matters.

If you keep it in a class implementing the IWorker interface, do reduce its accessibility level to at most protected, preferably to private. After all, whether a class implementing IWorker can handle some work is now an implementation detail of the Accept method and doesn’t have to be exposed any further than absolutely necessary.

When you no longer have a CanHandle method, you can simply write all the tests on the Accept method. It no longer matters how it determines its answer to whether it will do the work, just as long as it responds appropriately to the work it is handed.

That’s it. Enjoy!

What code had you wondering how to test it? I’d love hearing from you by email or in the comments below. I read everything and will try to help where and as best I can.



Leave a Reply

Your email address will not be published. Required fields are marked *

*

Show Buttons
Hide Buttons