Sending in an object of type Object instead of String - Polymorphism

孤街浪徒 提交于 2019-12-23 02:47:26

问题


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 (i.e. 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" 

回答1:


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.




回答2:


You can overload parseMessage so it comes in two flavors: one that takes a String argument and one that takes a MessageObject argument.




回答3:


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.




回答4:


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;
    }
});


来源:https://stackoverflow.com/questions/5134462/sending-in-an-object-of-type-object-instead-of-string-polymorphism

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!