将 switch 语句重构为多态代码

Refactoring the switch statements to polymorphic code

我的 API 具有发送多种消息的功能,例如,文本图像视频音频和富媒体内容。它们中的每一个都根据提供者的类型(提供发送消息的方法的人)的不同而不同地发送出去。 API 的设计如下,

interface Response{
     void sendTextMessage(String message);
     void sendPictureMessage(byte[] image);
     .....
     void sendRichMediaMessage(RichMedia message);
}

此 API 对不同的提供商处理和发送消息有不同的实现。但这种方法的真正问题是,一个提供者提供新类型的消息,而旧的提供者不提供,因此他们需要实现新方法并抛出 UnsupportedOperationException。所以我像下面这样重构它,

interface Response {
    void sendMessage(ResponseMessage message);
}
 abstract class ResponseMessage {
    ...
}
public class PlainTextResponse extends ResponseMessage {
   private String message=message;
   public PlainTextResponse(String message) {
      this.message=message;
   }
}

现在客户端发送这样的消息,

public static void main(String... str) {
    Response resp = ...;
    resp.sendMessage(new PlainTextMessage("Hello World!!!");
}

现在实现响应接口

class ResponseProvider1Impl implement Response {
    public ResponseProvider1Impl(ResponseProcessor processor) {
      this.processor=processor;
    }
    void sendMessage(ResponseMessage message) {
         // how do I get rid of this "if" block
         if(message instanceof PlainTextMessage) {
             processor.sendTextMessage(message.getData());
         } else if(message instanceof PictureMessage) {
              processor.sendPictureMessage(message.getData());
         }
        ......
    }
}

我认为 ResponseProcessor 会将很多东西从实际的 Response 接口中排除

interface ResponseProcessor  { 
   void sendTextMessage(String message);
     void sendPictureMessage(byte[] image);
     .....
     void sendRichMediaMessage(RichMedia message);
}

在我到达这里之前一切都很顺利,

class ResponseProcessorProvider1Impl implements ResponseProcessor   {
    void sendTextMessage(String message){// do things to send a text message}
     void sendPictureMessage(byte[] image){}
     .....
     void sendRichMediaMessage(RichMedia message){}
}

现在 问题: 我如何摆脱根据其类型检查和调用方法的 if 块?是的,我听到有人说,将其移至具有反射或枚举的工厂,以不使用 switch 或 if 语句,好吧,但这是正确的方法吗?你看到更好的设计方法了吗?我可以申请任何其他设计模式吗?

class ResponseProcessorProvider1Impl implements ResponseProcessor   {
     .....
     public void sendMessage(ResponseMessage message) {
         // how do I get rid of this "if" blocks
         if(message instanceof PlainTextMessage) {
             sendTextMessage(message.getData());
         } else if(message instanceof PictureMessage) {
              sendTextMessage(message.getData());
         }
     }
      ....
}

你对每个class调用相同的方法,这里不需要任何switch(if,elseif)条件,直接放

public void sendMessage(ResponseMessage message) {
         // how do I get rid of this "if" blocks
         sendTextMessage(message.getData());

     }

即使您需要调用不同的方法,我也会在每个 class 中创建一个具有相同名称的方法来调用正确的方法。

如果是这种情况,我会修改 PictureMessagePlainTextMessage、.. classes 添加一个名为 sendMessage,其中将包含每个 class 的特定代码,或者只是对特定方法的调用(sendPictureMessagesendTexMessage,...)

class PlainTextMessage->method sendMessage->calls sendTextMessage

因此无论 class 是什么,您都可以让界面始终调用 sendMessage。

public class DDMain {

    public static void main(String[] args) {
        MsgSender sender = new Provider$ASender();
        Resp resp = new RespImpl(sender);
        resp.sendMsg(new TxtMsg("hello world"));
        resp.sendMsg(new PicMsg(new byte[] { 'p', 'i', 'c' }));
    }
}

interface Resp {

    public void sendMsg(Msg msg);
}

class RespImpl implements Resp {

    private MsgSender sender;

    /**
     * 
     */
    public RespImpl(MsgSender sender) {
        this.sender = sender;
    }

    @Override
    public void sendMsg(Msg msg) {
        msg.sendWith(sender);
    }

}

interface Msg {

    byte[] getMsg();

    void sendWith(MsgSender sender);
}

class TxtMsg implements Msg {

    private String string;

    /**
     * @param string
     */
    public TxtMsg(String string) {
        this.string = string;
    }

    @Override
    public void sendWith(MsgSender sender) {
        sender.sendTxtMsg(this);
    }

    @Override
    public byte[] getMsg() {
        return string.getBytes();
    }
}

class PicMsg implements Msg {

    private byte[] data;

    /**
     * 
     */
    public PicMsg(byte[] data) {
        this.data = data;
    }

    @Override
    public void sendWith(MsgSender sender) {
        sender.sendPictureMsg(this);
    }

    /*
     * (non-Javadoc)
     * 
     * @see mgage.ott.middleware.newspec.Msg#getMsg()
     */
    @Override
    public byte[] getMsg() {
        return data;
    }
}

interface MsgSender {

    void sendTxtMsg(TxtMsg message);

    void sendPictureMsg(PicMsg rectangle);
}

// this class stays protected and wouldn't be available outside the api.
class Provider$ASender implements MsgSender {

    /**
     * 
     */
    public Provider$ASender() {
        // TODO Auto-generated constructor stub
    }

    @Override
    public void sendTxtMsg(TxtMsg message) {
        System.out.println("provider-A sending the txt message "
                + new String(message.getMsg()));
    }

    @Override
    public void sendPictureMsg(PicMsg message) {
        System.out.println("provider-A sending the pic message "
                + new String(message.getMsg()));
    }

}