mercredi 24 janvier 2018

OOP design - when to have a common base class [Flaw design?]

I have a simplified design as the following (basically a bunch of handlers to handle 2 different types of request: EventRequest and SpeechRequest). Below is the pseudocode:

class SpeechRequest {sessionId: String; slot: String}
class EventRequest {sessionId: String; event: String}

class SpeechRequestHandler; 
class EventRequestHandler;

class SpeechRequestHandler[A/B/C] extends SpeechRequestHandler {
    - handle(request: SpeechRequest) {      
        doSt(request.slot)
    }
}

class EventRequestHandler[A/B/C] extends EventRequestHandler {
    - handle(request: EventRequest) {       
        doSt(request.event)     
    }   
}

There is 2 different dispatchers to find appropriate handlers for each types of requests and forward them to handlers to handle:

class SpeechDispatcher {
    - handle(request: SpeechRequest) {
        handler: SpeechRequestHandler = findHandlerToHandle(request);
        handler.handle(request);
    }
}

class EventDispatcher {
    - handle(request: EventRequest) {
        handler: EventRequestHandler = findHandlerToHandle(request);
        handler.handle(request);
    }
}

Now, i want to refactor and create a base/common classes. Naturally, I came up with this:

class Request {sessionId: String}
class SpeechRequest extends Request {slot: String}
class EventRequest extends Request {event: String}

class RequestHandler {
    - canHandleRequest(Request): bool
    - handle(Request)
}

class SpeechRequestHandler extends RequestHandler {
    - canHandleRequest(request: Request): bool = request instanceof SpeechRequest
}

class EventRequestHandler extends RequestHandler {
    - canHandleRequest(request: Request): bool = request instanceof EventRequest
}

class SpeechRequestHandler[A/B/C] extends SpeechRequestHandler {
    - handle(Request: request) {
        //need to cast to specific type to extract a certain fields to do some operation
        //!! I feel something is not right because of that
        speechRequest:SpeechRequest = (SpeechRequest)request;
        doSt(speechRequest.slot)

        //other operation can work with base Request object; so it's OK
    }
}

class EventRequestHandler[A/B/C] extends EventRequestHandler {
    - handle(Request: request) {
        eventRequest:EventRequest = (EventRequest)request;
        doSt(eventRequest.event)

        //other operation can work with base Request object; so it's OK
    }   
}

The fact that for all SpeechRequestHandler[A/B/C]:handle functions, I now need to cast the Request object to (SpeechRequest) object specifically: speechRequest:SpeechRequest = (SpeechRequest)request;

I feel that there is flaw in my design. If every SpeechRequestHandler I need to cast the object to (SpeechRequest) so that I can do something with those info, does it means that it doesn't make sense to refactor a base class in this case ?

Please could you suggest a better way or a design pattern to handle this cleanly.

Thank you.

Aucun commentaire:

Enregistrer un commentaire