代码之家  ›  专栏  ›  技术社区  ›  meow

贬低或抛弃多态性——较小的邪恶是什么?

  •  2
  • meow  · 技术社区  · 8 年前

    假设我们有一个基类消息:

    public abstract Class Message {
    
        Object content;
    
        public Message(Object content) {
            this.content = content;
        }
    }
    

    public Class Packet extends Message {
    
        public Packet(Long largeNumber) {
            super(largeNumber);
        }
    
        public Long unpack() {
            return (Long) content;
        }
    }
    
    public Class Letter extends Message {
    
        public Letter(Short smallNumber) {
            super(smallNumber);
        }
    
        public Short unpack() {
            return (Short) content;
        }
    }
    

    现在假设我们有一个sender类,它将消息发送到某处。

    public Class Sender {
    
        public send(Message msg) {
            // send it somewhere
        }
    }
    

    public Class Receiver {
    
        receive(Message msg) {
           // do something with the msg 
       }
    }
    

    然而,receiver类只是获取超类消息,并且事先不知道它将接收哪个子类。那么我现在该如何“解包”信息呢?

    Packet packet = (Packet) msg;
    

    但不知何故,这让人感觉不对,因为它从一开始就忽视了多态性这一点。只发送绝对子消息是否更好? 或者,有没有解决我看不到的问题的方法(例如,在某些变体中使用泛型-我对它们不太熟悉)?

    4 回复  |  直到 8 年前
        1
  •  3
  •   Sergey Kalinichenko    8 年前

    解包消息可以由消息本身使用 visitor pattern :

    public abstract Class Message {
        void send(Receiver r) {
            r.receive(this); // Catch-all
        }
    }
    
    public Class Packet extends Message {
        void send(Receiver r) {
            r.receive(this); // Overload for packets
        }
    }
    
    public Class Letter extends Message {
        void send(Receiver r) {
            r.receive(this); // Overload for letters
        }
    }
    
    public Class Receiver {
        // There is an overload for each subclass
        receive(Packet packet) {
        }
        receive(Letter letter) {
        }
        // This is the catch-all implementation
        receive(Message msg) {
        }
    }
    

        2
  •  1
  •   Mordechai    8 年前

    要走的路是泛型:

    public abstract class Message<T> {
    
        private T content;
    
        public T unpack() {
            return content;
        }
    
    }
    
        3
  •  0
  •   Дима Годиков    8 年前

        public abstract class Message {
         public abstract String unpack();
         // other code
    }
    public class Letter extends Message {
        public String unpack() {
            // your unpacked code
        }
    }
    public class Receiver{
        receive(Message msg){
            String s = msg.unpack(); 
            /* you can invoke unpack method because earlier declared it as abstract in parent class */
        }
    }
    
        4
  •  0
  •   OutOfNPE    8 年前

    我建议为每种类型的消息创建处理程序的映射。 消息的内容不应丢失其类型。信息和信件示例:

    abstract class Message<T> {
        private T content;
        protected Message(T content) {
            this.content = content;
        }
        public T getContent() {
            return content;
        }
    }
    
    class Letter extends Message<Short> {
        public Letter(Short number) {
            super(number);
        }
    }
    

    interface MessageHandler<T extends Message> {
        void handle(T message);
    }
    

    class MessageHandlersProvider {
        Map<Class<? extends Message>, MessageHandler<? extends Message>> handlers = new HashMap<>();
        <T extends Message> void addHandler(Class<T> messageType, MessageHandler<T> handler) {
            handlers.put(messageType, handler);
        }
    
        MessageHandler<?> getHandler(Class<? extends Message> messageType) {
            return handlers.get(messageType);
        }
    }
    

    class LetterHandler implements MessageHandler<Letter> {
        @Override
        public void handle(Letter letter) {
            //Short number = letter.getContent();
            //do anything
        }
    }
    

    现在,您可以创建提供者,并通过处理程序按以下方式填充它:

    MessageHandlersProvider handlersProvider = new MessageHandlersProvider();
    handlersProvider.addHandler(Letter.class, new LetterHandler());
    

    然后获取处理程序并处理任何类型的消息:

    MessageHandler<?> handler = handlersProvider.getHandler(message.getClass());
    handler.handle(message);