1

I'm studying about polmorphism and interface oriented design and I'm having problems to make my class execute the proper method according the object received, to avoid using insntanceOf or typecasting.

I made a interface which represents a collection of Envelope (a wrapper to a text), and in this interface I have this method:

Interface Envelopes{
    public void add(Envelope envelope);
}

My intent is to override this method in each implementation to allow each implementation to use a particular type to access envelope data. For example, I implemented it this way in my class EnvelopesWithColor (which stores envelopes with color info):

Interface EnvelopesWithColor extends Envelope{

    public  void add(EnvelopeWithColor envelope) {
        System.out.println("ADDING ENVELOPE WITH COLOR" + envelope.getClass());
    }

    @Override
    public void add(Envelope envelope) {
        System.out.println("ADDING ENVELOPE " + envelope.getClass());
    }
}

So far, so good. To avoid coupling I want do declare a Envelopes object, and start to add envelopes to it, for example.

Envelopes envelopes = new EnvelopesWithColor();

envelopes.add(new SimpleEnvelope("some text"));
envelopes.add(new SimpleEnvelopeWithColor(new SimpleEnvelope("some text with color"));

The problem is: if I instantiate Envelope using the Interface type, it does not realize what type of object is being passed and just executes the add(Envelope envelope) even when I am providing a EnvelopeWithColor, printing the result below:

ADDING ENVELOPE class SimpleEnvelope
ADDING ENVELOPE class SimpleEnvelopeWithColor

On the other hand, if I directly instantiate my Envelopes type...

new EnvelopesWithColor().add(new SimpleEnvelope("some text"));
new EnvelopesWithColor().add(new SimpleEnvelopeWithColor(new SimpleEnvelope("some text with color"));

I have this output:

ADDING ENVELOPE class SimpleEnvelope
ADDING ENVELOPE WITH COLOR class SimpleEnvelopeWithColor

Having the implementation Envelopes type defined outputs the correct result too:

EnvelopesWithColor envelopes = new EnvelopesWithColor();
envelopes.add(new SimpleEnvelope("some text"));
envelopes.add(new SimpleEnvelopeWithColor(new SimpleEnvelope("some text with color"));

Results in:

ADDING ENVELOPE class SimpleEnvelope
ADDING ENVELOPE WITH COLOR class SimpleEnvelopeWithColor

There is some (elegant) way to discover which implementation of the Envelopes interface is being sent to my add() method (by elegant I mean not using instanceof / typecasting)? I've tryed a lot of ways with generic subtyping, generic methods, wrapper methods and did not succeed. Why the implementation is not receiving the actual objects?

4
  • "by elegant I mean not using instanceof" why you think that using instanceof is not elegant? Commented Jan 5, 2018 at 19:38
  • Thats because your variable is of type Envelope which only knows of add(Envelope). Overloading won't work unless both methods are defined in the public interface. As for the solution, you could either use the visitor pattern or stick with instanceof Commented Jan 5, 2018 at 19:44
  • @JuanCarlosMendoza Because if you use an instanceof "switch", it will need to be changed if a new class is added. The difference in behavior should be implemented in a common interface method, so a new class brings along its own "case". Commented Jan 6, 2018 at 9:04
  • @daniu is right. I'm trying to strongly enforce the open-closed principle (open for extension, closed for modification), and for this reason I don't want to use a instanceof switch. Commented Jan 8, 2018 at 17:10

2 Answers 2

1

You are getting polymorphism wrong.

Polymorphism is only about the object a method is called on.

The types of parameters do not play a role in polymorphism. In other words: polymorphism is not the same thing as overloading! (in the more narrow Java sense - as Vince nicely points out, conceptually overloading can be seen as "ad hoc polymorphism").

In that sense: with Java, you either need that instanceof check - or you have to turn your logic around. Instead of doing overloading on the Envelopes class you use a polymorphic method on the Envelope class. And then colored envelope objects behave differently.

Sign up to request clarification or add additional context in comments.

2 Comments

Overloading is ad-hoc polymorphism. It is a form of polymorphism
I see. Actually I was trying to add some Envelope and my "Envelope container" (Envelopes) would know how to properly save or persist the object, and for that it should be able to discover its proper type (for saving color information, for example). I guess that I'll have to do all the other way around, with my object saving itself to the "Envelope container".
1

As GhostCat said, you got it the wrong way around. You do this :

class Envelopes {
    public void add(Envelope env) {
        System.out.println("adding" + env.getDescription());
    }
}
interface Envelope {
    String getDescription() ;
}
class NormalEnvelope implements Envelope {
    public String getDescription () {
        return "envelope" ;
}}
class EnvelopeWithColor implements Envelope {
    public String getDescription () {
        return "envelope with color" ;
}}

The thing is, the way you do it, is the compiler that resolves which method is called, not the runtime.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.