我有以下情况:客户端类根据它接收的消息类型执行不同的行为。我想知道是否有更好的方法,因为我不喜欢instanceof和if语句。
我想做的一件事就是将方法拉出客户端类并将它们放入消息中。我会在IMessage接口中放入一个类似process()的方法,然后将消息特定的行为放在每个具体的消息类型中。这会使客户端变得简单,因为它只调用message.process()而不是检查类型。但是,唯一的问题是条件中包含的行为与对Client类中包含的数据的操作有关。因此,如果我在具体的消息类中实现了一个进程方法,我将不得不将它传递给客户端,我不知道这是否真的有意义。
public class Client {
messageReceived(IMessage message) {
if(message instanceof concreteMessageA) {
concreteMessageA msg = (concreteMessageA)message;
//do concreteMessageA operations
}
}
if (message instanceof concreteMessageB) {
concreteMessageb msg = (concreteMessageB)message;
//do concreteMessageB operations
}
}
答案 0 :(得分:7)
避免实例测试的简单方法是多态分派; e.g。
public class Client {
void messageReceived(IMessage message) {
message.doOperations(this);
}
}
其中每个消息类定义适当的doOperations(Client client)
方法。
编辑:第二种解决方案,更符合要求。
用switch语句替换'instanceof'测试序列的替代方法是:
public class Client {
void messageReceived(IMessage message) {
switch (message.getMessageType()) {
case TYPE_A:
// process type A
break;
case TYPE_B:
...
}
}
}
每个IMessage类都需要定义int getMessageType()
方法以返回适当的代码。 Enum的工作方式也很好,IMO更优雅。
答案 1 :(得分:4)
此处的一个选项是处理程序链。您有一系列处理程序,每个处理程序都可以处理一条消息(如果适用),然后使用它,这意味着它不会在链中进一步传递。首先定义Handler
接口:
public interface Handler {
void handle(IMessage msg);
}
然后处理程序链逻辑看起来像:
List<Handler> handlers = //...
for (Handler h : handlers) {
if (!e.isConsumed()) h.handle(e);
}
然后每个处理程序可以决定处理/使用事件:
public class MessageAHandler implements Handler {
public void handle(IMessage msg) {
if (msg instanceof MessageA) {
//process message
//consume event
msg.consume();
}
}
}
当然,这并没有摆脱instanceof
- 但它确实意味着你没有一个巨大的if-elseif-else-if-instanceof
块,这可能是不可读的
答案 2 :(得分:1)
您使用的是什么类型的邮件系统?
许多人都可以根据邮件标题或内容向处理程序添加过滤器。如果支持这一点,你只需创建一个带有基于消息类型的过滤器的处理程序,那么你的代码就很好而且干净,而不需要instanceof或check类型(因为消息传递系统已经为你检查了它)。
我知道您可以在JMS或OSGi事件服务中执行此操作。
由于您使用的是JMS,因此基本上可以执行以下操作来注册侦听器。这将为每个唯一的消息类型创建一个侦听器。
String filterMsg1 = "JMSType='messageType1'";
String filterMsg2 = "JMSType='messageType2'";
// Create a receiver using this filter
Receiver receiverType1 = session.createReceiver(queue, filterMsg1);
Receiver receiverType2 = session.createReceiver(queue, filterMsg2);
receiverType1.setMessageHandler(messageType1Handler);
receiverType2.setMessageHandler(messageType2Handler);
现在每个处理程序将只接收特定的消息类型(没有instanceof或if-then),当然假设发送者通过调用setJMSType()对传出消息设置类型。
此方法内置于消息中,但您当然可以创建自己的标题属性并对其进行过滤。
答案 3 :(得分:0)
//Message.java
abstract class Message{
public abstract void doOperations();
}
//MessageA.java
class MessageA extends Message{
public void doOperations(){
//do concreteMessageA operations ;
}
}
//MessageB.java
class MessageB extends Message {
public void doOperations(){
//do concreteMessageB operations
}
}
//MessageExample.java
class MessageExample{
public static void main(String[] args) {
doSmth(new MessageA());
}
public static void doSmth(Message message) {
message.doOperations() ;
}
}
答案 4 :(得分:0)
使用双重调度的Java 8解决方案。没有完全摆脱instanceof
,但每条消息只需要一次检查,而不是if-elseif链。
public interface Message extends Consumer<Consumer<Message>> {};
public interface MessageA extends Message {
@Override
default void accept(Consumer<Message> consumer) {
if(consumer instanceof MessageAReceiver){
((MessageAReceiver)consumer).accept(this);
} else {
Message.super.accept(this);
}
}
}
public interface MessageAReceiver extends Consumer<Message>{
void accept(MessageA message);
}
答案 5 :(得分:0)