Jake Conkerton-Darby
Jake Conkerton-Darby

Reputation: 1101

Software pattern to return concrete result from abstractions

So I'm trying to work out how (or if it's even possible) to put together a particular software architecture with some unconventional requirements. The architecture has a service layer and potentially multiple client layers that use the service layer.

What I would like is the service layer to take in an abstraction, and return an abstraction with concrete implementations defined by the client layers in such a way as the clients can get whatever specific result they need without the service layer having any knowledge of the type of output needed.

I can solve this problem using generics or marker interfaces and direct casting results, but both of these are suboptimal for my goals, and I was hoping someone here would have the inspiration I'm lacking.

This is a rough example of the overall structure of the abstractions in play, but is all open to revision if a suitable solution requires it:

interface IServiceResult {
    // No idea what methods this should have yet
}

interface IServiceHandler {
    IServiceResult CouldNotFindFile();
    IServiceResult CouldNotReadFile();
    IServiceResult ServiceSuccessful();
}

interface IService {
    IServiceResult PerformService(IServiceHandler outcomes);
}

// Console Client Code:
IService service = new Service();
IServiceHandler handler = new ConsoleServiceHandler();
IServiceResult result = service.PerformService(handler);
/* Some process to convert IServiceResult to text to display in the console */

// API Endpoint Client Code:
IService service = new Service();
IServiceHandler handler = new ApiServiceHandler();
IServiceResult result = service.PerformService(handler);
/* Some process to convert IServiceResult to Http Status Code to return to client */

My intuition is to have some sort of double dispatch with the IServiceResult but I can't work out of/how to end up with the desired result from that point on. Any insight would be most appreciated.

Upvotes: 0

Views: 30

Answers (1)

Matt Timmermans
Matt Timmermans

Reputation: 59293

The problem with what you're trying to do is that the concrete types of result and handler need to correspond, and there isn't a way in the language's type system to express that constraint. If you try to use double dispatch, you'll end up with an interface that has methods for each concrete type, and that's a pain to maintain.

It would be better to use a design that doesn't require that constraint in the first place.

You can simplify your interface and avoid this problem by getting rid of IServiceResult altogether

interface IServiceResponder {
    void CouldNotFindFile();
    void CouldNotReadFile();
    void ServiceSuccessful();
}

interface IService {
    void PerformService(IServiceResponder responseTarget);
}

// Console Client Code:
IService service = new Service();
// this will print the response to the console when it is set
IServiceResponder responder = new ConsoleServiceResponder();
service.PerformService(responder);

Upvotes: 1

Related Questions