将switch语句重构为多态代码

时间:2015-04-09 14:16:19

标签: java design-patterns conditional-statements

我的功能是我的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!!!");
}

现在实施一个Response接口

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块?是的,我听到有人说,把它移到有反射或枚举的工厂,不要使用开关或if语句,好吧,但这是正确的方法吗?你有没有看到更好的设计方法?我可以申请的任何其他设计模式吗?

2 个答案:

答案 0 :(得分:0)

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());
         }
     }
      ....
}

你正在为每个类调用相同的方法,这里不需要任何开关(if,elseif)条件,只需直接放入

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

     }

即使在你需要调用另一个方法的情况下,我也会在每个类中创建一个方法,该方法具有相同的名称,可以调用正确的方法。

如果是这种情况,我会修改 PictureMessage PlainTextMessage ,..类添加一个名为 sendMessage 的新方法,它将包含特定的每个类的代码,或者只是对特定方法的调用( sendPictureMessage sendTexMessage ,...)

  

class PlainTextMessage->方法sendMessage->调用sendTextMessage

所以你可以保持接口总是调用sendMessage,无论类是什么。

答案 1 :(得分:0)

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()));
    }

}