简体   繁体   English

发送类型为Object而不是String的对象-多态

[英]Sending in an object of type Object instead of String - Polymorphism

I've an existing method which looks like this: 我有一个看起来像这样的现有方法:

  public void parseMessage(String message){
    ...
    ...
    ...
  }

and the method is called by calling it as shown below 并通过如下所示调用该方法

 String message;
 parseMessage(message);

I need to modify it for it to process a new type of message. 我需要对其进行修改以处理新型消息。 The parser for the new type of message which is called from the parseMessage method expects some properties first before it can parse the message. 从parseMessage方法调用的新型消息的解析器在解析消息之前首先需要一些属性。 What i am thinking of doing is passing the message as an object that looks like this 我正在想做的是将消息传递为看起来像这样的对象

public class MessageObject{
  private String message;
  private String namespace;
  private String xmlVersion;
}

I can then call the existing method as 然后我可以将现有方法称为

 Object messageObject;
 parseMessage(messageObject);

I can then use it on the other side by casting it as (MessageObject)messageObject. 然后,我可以通过将其强制转换为(MessageObject)messageObject来使用它。

Is this the correct way of doing it or is there a better approach. 这是正确的做法还是有更好的办法? Are there any dangers to doing the above? 进行上述操作有危险吗?

ps. ps。 i have to use the above casting approach as im using JDK1.4 我必须像使用JDK1.4一样使用上述转换方法

Thanks 谢谢

Update 更新资料

I cant modify the parseMessage method. 我无法修改parseMessage方法。 It has a call inside it which calls the parse() method for each relevant parser. 它内部有一个调用,该调用为每个相关的解析器调用parse()方法。

 public void parseMessage(String message){
    ...
    ...
    parser.parse(message)
  }

The parser reference shown above is an object that implements an interface "Parser". 上面显示的解析器参考是一个实现接口“解析器”的对象。 The new parser i am introducing follows this structure and it also implements the "Parser" interface. 我要介绍的新解析器遵循此结构,并且还实现了“解析器”接口。 The only modifications (ie the casting to MessageObject) are in the new parser. 唯一的修改(即,强制转换为MessageObject)在新的解析器中。

i cant change the existing parseMethod as that will require changing all of the existing parsers that implement the "Parser" interface. 我无法更改现有的parseMethod,因为这将需要更改所有实现“ Parser”接口的现有解析器。 I want to avoid having to call a specific parser depending on message type. 我想避免必须根据消息类型调用特定的解析器。

If i use the approach i am suggesting, existing parsers will still recieve a String message while the new parser will recieve a String but it will need to cast it back to MessageObject first. 如果我使用我建议的方法,则现有的解析器仍将接收到String消息,而新的解析器将接收到String,但需要首先将其强制转换回MessageObject。

Edit 编辑

I have had to test this based on Sergey's comments. 我不得不根据谢尔盖的评论对此进行测试。

The Interface 介面

    package com;
    public interface Parser{
        public void parse(String message);
    }


    package com;

MessageA Parser MessageA解析器

    public class MessageAParser implements Parser{
        public void parse(String message){
            System.out.println("Parsing A");
        }
    }

MessageB Parser MessageB解析器

    package com;

    public class MessageAParser implements Parser{
        public void parse(String message){
            System.out.println("Parsing A");
        }
    }

MessageC parser (This expects an object) MessageC解析器(这需要一个对象)

    package com;
    public class MessageCParser implements Parser{
        public void parse(Object message){
            MessageObject mobject = (MessageObject)message; 
            System.out.println("Parsing C" + mobject.getMessage());
        }

        public void parse(String m){}
    }

The parser manager that calls the relevant parser. 调用相关解析器的解析器管理器。

    package com;

    import java.util.HashMap;

    public class ParserManager{

        public ParserManager() {
            prepare();
        }

        HashMap parsers = new HashMap();


        public void prepare(){

            parsers.put("A",new MessageAParser());
            parsers.put("B",new MessageBParser());
            parsers.put("C",new MessageCParser());
        }

        public void parseMessage(String msgType, String message){
            ((Parser)parsers.get(msgType)).parse(message);
        }
    }


    package com;

The controller. 控制器。

    public class ControlClass{

        public static void main(String[] args){

            ParserManager pManager = new ParserManager();

            //Parse A
            pManager.parseMessage("A","ATEXT TO PARSE");

            //Parse B
            pManager.parseMessage("B","BTEXT TO PARSE");

            //Parse C
            Object mobject = new MessageObject();
            pManager.parseMessage("C",(String)mobject);
        }
    }

When i run the above Controller class it outputs the text for the first two messages but fails for the third one. 当我运行上面的Controller类时,它输出前两个消息的文本,但输出第三个消息失败。

Parsing A
Parsing B
java.lang.ClassCastException
    at com.ControlClass.main(ControlClass.java:17)
Exception in thread "main" 

您可以重载parseMessage,因此它具有两种形式:一种带有String参数,另一种带有MessageObject参数。

The MessageObject class is not a String subclass, so you can't pass it instead of String. MessageObject类不是String子类,因此您不能传递它而不是String。 And you can't subclass String since it's declared as final. 而且您不能继承String,因为它已声明为final。 So there is no way you can pass a MessageObject (whatever that is) to the existing parseMessage() function. 因此,您无法将MessageObject(无论是什么)传递给现有的parseMessage()函数。

i cant change the existing parseMethod as that will require changing all of the existing parsers that implement the "Parser" interface. 我无法更改现有的parseMethod,因为这将需要更改所有实现“ Parser”接口的现有解析器。 I want to avoid having to call a specific parser depending on message type. 我想避免必须根据消息类型调用特定的解析器。

What exactly is the signature of the Parser.parse()? Parser.parse()的签名到底是什么? If it's parse(String message) , then you can't possibly pass there anything else than a String. 如果它是parse(String message) ,那么除了String之外,您不可能再传递其他任何内容。

However, if that's the only reason you don't want to modify the existing parseMessage(), then there is a workaround: 但是,如果这是您不想修改现有parseMessage()的唯一原因,那么有一种解决方法:

public void parseMessage(Object message) { // changed to Object
  ...
  ...
  if (message instanceof String)
    parser.parse((String) message);
  else {
    if (message instanceof MessageObject) {
      if (!(parser instanceof MessageObjectParser)) {
        throw new IllegalArgumentException(
          "A MessageObject is passed, but not supported by the parser");
      }
      ((MessageObjectParser) parser).parse((MessageObject) message);
    } else {
      throw new IllegalArgumentException(
        "Messages of type " + parser.getClass() + " aren't supported");
    }
  }
}

It's a bit ugly, but will probably work. 这有点难看,但可能会起作用。 Now you only have your new parsers implement the new MessageObjectParser interface, which should extend the old Parser. 现在,只有新的解析器实现新的MessageObjectParser接口,该接口应该扩展旧的解析器。

I think there a couple of cleaner solutions here. 我认为这里有一些更清洁的解决方案。 The first is that you could extend the class that implements parseMessage and add an additional method. 第一个是您可以扩展实现parseMessage的类并添加其他方法。

public void parseMessage(MessageObject messageObject) {
  // Additional stuff here
  ...

  // Call through to original
  parseMessage(messageObject.message);
}

Alternatively, you could just decorate the class that contains parseMessage. 或者,您可以装饰包含parseMessage的类。 However, I am assuming that you can modify the class that contains parseMessage since you say you want to cast it in there anyway. 但是,我假设您可以修改包含parseMessage的类,因为您说过无论如何都要将其转换为该类。

If you have more and more types of things to parse, instead of overloading the parse method, you should introduce an interface : 如果您要解析的事物类型越来越多,则应该引入一个接口来代替重载parse方法:

public interface Parseable {
    public String getMessage();
}

The MessageObject would implement Parseable, and you could use an anonymous adapter class for String objects : MessageObject将实现Parseable,并且您可以对String对象使用匿名适配器类:

final String m = "theMessageToParse";
parseMessage(new Parseable() {
    public String getMessage() {
        return m;
    }
});

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM