检查消息类型时避免使用instanceof

vol*_*238 9 java polymorphism instanceof messages

我有以下情况,其中客户端类根据它接收的消息类型执行不同的行为.我想知道是否有更好的方法,因为我不喜欢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
        }
}
Run Code Online (Sandbox Code Playgroud)

Ste*_*n C 7

避免实例测试的简单方法是多态分派; 例如

public class Client {
    void messageReceived(IMessage message) {
        message.doOperations(this);
    }
}
Run Code Online (Sandbox Code Playgroud)

每个消息类定义适当的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:
           ...
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

每个IMessage类都需要定义一个int getMessageType()方法来返回适当的代码.Enum的工作方式也很好,IMO也更优雅.

  • 如果访问属性仅在消息子类型上可用时需要不同的* process *块,则第二种方法可能仍需要强制转换 (2认同)

oxb*_*kes 5

这里的一个选择是处理程序链。您有一连串的处理程序,每个处理程序都可以处理一条消息(如果适用)然后使用它,这意味着该消息将不会在该链中进一步传递。首先定义Handler接口:

public interface Handler {
    void handle(IMessage msg);
}
Run Code Online (Sandbox Code Playgroud)

然后,处理程序链逻辑如下所示:

List<Handler> handlers = //...
for (Handler h : handlers) {
    if (!e.isConsumed()) h.handle(e);
}
Run Code Online (Sandbox Code Playgroud)

然后,每个处理程序可以决定处理/使用一个事件:

public class MessageAHandler implements Handler {
    public void handle(IMessage msg) {
        if (msg instanceof MessageA) {
            //process message
            //consume event 
            msg.consume();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

当然,这并不能摆脱instanceofs-但这确实意味着您没有巨大的if-elseif-else-if-instanceof块,这可能是不可读的