我有一个简化的设计如下(基本上是一堆处理2种不同类型的请求的处理程序:EventRequest和SpeechRequest)。下面是伪代码:
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)
}
}
有两种不同的调度程序可以为每种类型的请求找到合适的处理程序,并将它们转发给处理程序来处理:
class SpeechDispatcher {
- handle(request: SpeechRequest) {
handler: SpeechRequestHandler = findHandlerToHandle(request);
handler.handle(request);
}
}
class EventDispatcher {
- handle(request: EventRequest) {
handler: EventRequestHandler = findHandlerToHandle(request);
handler.handle(request);
}
}
现在,我想重构并创建一个基类/公共类。当然,我想出了这个:
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
}
}
对于所有SpeechRequestHandler [A / B / C]:处理函数的事实,我现在需要具体地将Request对象转换为(SpeechRequest)对象:speechRequest:SpeechRequest =(SpeechRequest)请求;
我觉得我的设计存在缺陷。如果每个SpeechRequestHandler我需要将对象转换为(SpeechRequest)以便我可以对这些信息做些什么,这是否意味着在这种情况下重构基类没有意义?
请你建议一个更好的方法或设计模式来干净利落地处理这个问题。
谢谢。
答案 0 :(得分:0)
如果你想保持类型安全,你可以通过双重调度来做这种事情。见https://en.wikipedia.org/wiki/Double_dispatch
看起来你想要这样的东西:
interface HandlerSet{
SpeechHandler getSpeechHandler(Request request);
EventHandler getEventHandler(Request request);
}
abstract Request {
... common stuff ...
abstract handleWith(HandlerSet handlers);
}
class SpeechRequest extends Request {
sessionId: String; slot: String
handleWith(HandlerSet handlers) {
return handlers.getSpeechHandler(this).handle(this);
}
}
class EventRequest extends Request {
sessionId: String; event: String
handleWith(HandlerSet handlers) {
return handlers.getEventHandler(this).handle(this);
}
}
答案 1 :(得分:0)
主要问题是你引入了一个可以用Request
的每种类型调用的方法,但请求的具体处理程序必须知道具体的类型。
像这样的东西
public void handleRequest(Request request){
// Find the correct handler
for(RequestHandler requestHandler : requestHandlers){
if(requestHandler.canHandle(request)){
// Opps, the handler needs the concrete type
requestHandler.handle(request);
}
}
}
在运行时,唯一有足够信息知道哪个处理程序可以处理它的对象是Request
。因此,您必须要求请求选择要调用的特定目标方法。
这称为visitor pattern
。
public interface Request {
public void accept(RequestVisitor requestVisitor);
}
public interface RequestVisitor {
public void visit(SpeechRequest speechRequest);
public void visit(EventRequest eventRequest);
}
Request
实现现在可以决定必须调用RequestVisitor
的哪个回调:
public class SpeechRequest implements Request {
public void accept(RequestVisitor requestVisitor) {
requestVisitor.visit(this);
}
}
public class EventRequest implements Request {
public void accept(RequestVisitor requestVisitor) {
requestVisitor.visit(this);
}
}
然后具体的处理程序可以使用具体的请求对象
public class SpeechRequestHandler {
public void handle(SpeechRequest request) {
System.out.println(request.getClass().getSimpleName());
}
}
public class EventRequestHandler {
public void handle(EventRequest request) {
System.out.println(request.getClass().getSimpleName());
}
}
从客户的角度来看,访问者可能会像这样使用:
SpeechRequestHandler speechRequestHandler = new SpeechRequestHandler();
EventRequestHandler eventRequestHandler = new EventRequestHandler();
RequestVisitor requestVisitor = new RequestVisitor() {
@Override
public void visit(EventRequest eventRequest) {
eventRequestHandler.handle(eventRequest);
}
@Override
public void visit(SpeechRequest speechRequest) {
speechRequestHandler.handle(speechRequest);
}
};
Request request1 = new SpeechRequest();
Request request2 = new EventRequest();
request1.accept(requestVisitor);
request2.accept(requestVisitor);
但是使用访问者模式通常(但并不总是)提示您尝试使界面过于抽象。这就是为什么你丢失了以后需要重新创建的类型信息。也许你会找到更好的设计。