简体   繁体   中英

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. 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.

Is this the correct way of doing it or is there a better approach. Are there any dangers to doing the above?

ps. i have to use the above casting approach as im using JDK1.4

Thanks

Update

I cant modify the parseMessage method. It has a call inside it which calls the parse() method for each relevant parser.

 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.

i cant change the existing parseMethod as that will require changing all of the existing parsers that implement the "Parser" interface. 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.

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

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

MessageB Parser

    package com;

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

MessageC parser (This expects an object)

    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.

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. And you can't subclass String since it's declared as final. So there is no way you can pass a MessageObject (whatever that is) to the existing parseMessage() function.

i cant change the existing parseMethod as that will require changing all of the existing parsers that implement the "Parser" interface. I want to avoid having to call a specific parser depending on message type.

What exactly is the signature of the Parser.parse()? If it's parse(String message) , then you can't possibly pass there anything else than a String.

However, if that's the only reason you don't want to modify the existing parseMessage(), then there is a workaround:

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.

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.

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. However, I am assuming that you can modify the class that contains parseMessage since you say you want to cast it in there anyway.

If you have more and more types of things to parse, instead of overloading the parse method, you should introduce an interface :

public interface Parseable {
    public String getMessage();
}

The MessageObject would implement Parseable, and you could use an anonymous adapter class for String objects :

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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