将 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 中创建一个具有相同名称的方法来调用正确的方法。
如果是这种情况,我会修改 PictureMessage、PlainTextMessage、.. classes 添加一个名为 sendMessage,其中将包含每个 class 的特定代码,或者只是对特定方法的调用(sendPictureMessage,sendTexMessage,...)
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()));
}
}
我的 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 中创建一个具有相同名称的方法来调用正确的方法。
如果是这种情况,我会修改 PictureMessage、PlainTextMessage、.. classes 添加一个名为 sendMessage,其中将包含每个 class 的特定代码,或者只是对特定方法的调用(sendPictureMessage,sendTexMessage,...)
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()));
}
}