3

I'm sure there's some solution or pattern to this but i'm having trouble articulating the question to find the right answer.

I have an interface, ICar:

public interface ICar {
void SetMake(String make);
String GetMake();
}

I have a class, Car:

public class Car implements ICar {
private String make;

public void SetMake(String make) { this.make = make; }

public String GetMake() { return make; }

And I have a method in another class, which does not know about Car. In the spirit of polymorphism I'd like this method to return an ICar, so that someone could create their own implementation of ICar and utilize the method for their car:

...//class preamble
public ICar myMethod() {
    ICar myCar = new ICar();
    myCar.SetMake("Ferrari");
    return myCar;
}

I'm not sure why something like this can't work. As ICar contains the method SetMake, every implementation must also contain this method. Surely the jvm could in some way queue up the method calls and then run them when a concretion of the methods is available?

Another idea would be to pass a newly created implementation of ICar as a parameter to myMethod and call its methods, but I feel like this may not be such a clean implementation, as I would need to create an instance of Car each time. Also if there is no parameter-less constructor, i would have to instantiate it with dummy data (also not clean).

I feel like i'm lacking some understanding to see how to implement something like this, and was wondering if anyone might be able to help?

Thanks.

Tom
  • 508
  • 4
  • 16

6 Answers6

1

One way to do this is to provide the class type as a parameter, and also make it generic:

public <T extends ICar> T myMethod(Class<T> type) {
    try {
        T myCar = type.newInstance(); // T needs a visible no-args constructor
        myCar.SetMake("Ferrari");
        return myCar;
    } catch (Exception e) {
        throw new RuntimeException(e);
    }
}

(note also that I dealt with exceptions by wrapping any in a RuntimeException)

Then you need to call it like this:

Car car = myMethod(Car.class);

A more flexible way is to introduce a factory interface and pass a factory instance to myMethod, which uses it to create a concrete ICar. The factory can still be generic:

public interface ICarFactory<T extends ICar> {
    T createCar();
}

...

public <T extends ICar> T myMethod(ICarFactory<T> factory) {
    T myCar = factory.createCar();
    myCar.SetMake("Ferrari");
    return myCar;
}

...

Car car = myMethod(carFactory);
Jordão
  • 55,340
  • 13
  • 112
  • 144
  • 1
    Thanks, I like this answer for being less obvious and demonstrating the implementation. I think i'll go the Factory route. – Tom Mar 31 '16 at 12:15
0

You need to do:

public ICar myMethod() {
    ICar myCar = new Car();
    myCar.SetMake("Ferrari");
    return myCar;
}

instead of

public ICar myMethod() {
    ICar myCar = new ICar();
    myCar.SetMake("Ferrari");
    myCar.return;
}

this statement: myCar.return; makes almost no sense here... and since ICar is an interface you can not do ICar myCar = new ICar()

ΦXocę 웃 Пepeúpa ツ
  • 47,427
  • 17
  • 69
  • 97
  • `new ICar();` will not compile, as it's an interface. – starf Mar 30 '16 at 18:40
  • Sorry I made an error with myCar.return. This doesn't solve the problem however as myMethod cannot know about the Car type. – Tom Mar 30 '16 at 18:47
0

You cannot instantiate an Interface, so new ICar() is not an option. For example, the setMake is supposed to set an instance variable, but an Interface has no instance variables.

However, you can do something like:

        return new ICar() {
        String m;
        @Override
        public void setMake(String make)
        {
            m = make;
        }



        @Override
        public String getMake()
        {
            return m;
        }
    };

In this way you are create an object that implements the interface.

While this answer gives a particular example to answer the question (as does simply instantiating a Car object), the larger question about the interface is that one can return any Object that implements in the interface. There are any number of design patterns than allow for delegating creation of objects. One might consider the Factory Pattern for example.

Community
  • 1
  • 1
KevinO
  • 4,303
  • 4
  • 27
  • 36
  • Could this be 'converted' to the Car type after returning? So i could call myMethod like: `Car newCar = myMethod();` ? – Tom Mar 30 '16 at 18:46
  • @RicketyRick No, the method returns the `interface`, not a specific class. So, the call would be `ICar newCar = myMethod()`. It is generally better to [Program to Interfaces, Not Implementations](http://stackoverflow.com/questions/2697783/what-does-program-to-interfaces-not-implementations-mean), so it is better to use the interface methods, not a specific class implementation. – KevinO Mar 30 '16 at 18:48
  • Is there any way of doing `Car newCar = myMethod();` without myMethod knowing about the concrete Car type? (other than passing a new Car as parameter) – Tom Mar 30 '16 at 18:51
  • @RicketyRick, no, since `Car` is a specific class. The better course is to use the `interface ICar` rather than the specific class `Car`. However, I am making some assumptions about the way you are using the word "type" that may be incorrect. The best approach, I believe, is to use a Factory Pattern for myMethod, returning `ICar`, and allowing the Factory to return the specific/concrete instantiation of `ICar`. – KevinO Mar 30 '16 at 18:57
0

You can't create a new interface but you can return one.

public ICar myMethod() {
    ICar myCar = new Car();
    myCar.SetMake("Ferrari");
    return myCar;
}

Interface means a contract it's basically saying "This is a ICar it can be Car, RedCar and a thousand different implementations but you don't know which" . This is the meaning of polymorphism whoever uses myMethod has no idea which car he gets, he can only know the contract but not how they are implemented.

  • In this scenario myMethod() doesn't know about the Car class. I wanted to do something like `Car myCar = myMethod()` where SetMake() is called on myCar, without using dependency injection. This may not even be possible, which is why i'm asking. – Tom Mar 30 '16 at 19:16
  • You are missing the point of interface and polymorphism. if you want to use `Car myCar = myMethod()` you can do it by changing the signature to return `Car` and not `ICar', BUT lets say that tomorrow you decide to change `myMethod()` to create new `RedCar` so now you need to change the signature and whoever use `myMethod` which can be in a lot of places. By using return value of `ICar` you are solving this problem (known as encapsulation) if you change `myMethod` to create a `RedCar` all your code remain the same because `RedCar implements ICar` this is the way to use interfaces. – Amir Taboul Mar 30 '16 at 19:19
0

Not really sure if I understand what you're after exactly, but I think what you really want to do is inherit your Car from an abstract base class, so that someone else can implement other types of vehicles.

Something like this:

public abstract class Vehicle {
    public abstract void SetMake(String make);
    public abstract String GetMake();
}

public class Car extends Vehicle {
    private String make;
    public void SetMake(String make) { this.make = make; }
    public String GetMake() { return make; }
}

public class Truck extends Vehicle {
    private String make;
    public void SetMake(String make) { this.make = make; }
    public String GetMake() { return make; }
}



public Vehicle myMethod() {
    Vehicle myCar = new Truck();
    myCar.SetMake("Ferrari");
    return myCar;
}    
Magnus
  • 17,157
  • 19
  • 104
  • 189
  • True, one could go this hierarchy, but I would still create the interface IVehicle, and have myMethod() return that. This example also repeats the `String make` in both subclasses, where it could be handled in the base. The approach here still leaves one programming to a particular implementation. – KevinO Mar 30 '16 at 18:53
0

For the method myMethod() you have stated

"In the spirit of polymorphism I'd like this method to return an ICar, so that someone could create their own implementation of ICar and utilize the method for their car:"

What I understand from this is you wish to make myMethod() work with different concrete types of ICar.

Objects are created when you use new operator. Your existing code would not compile as you can not instantiate the object of Interfaces. To fix the compile error I would not like you to to create the concrete car objects:

ICar car = new Car(); // this will solve compile error but avoid doing this in your code

Avoid new operator, let the user of your code use new and inject the concrete implementations (you may not even know the concrete implementations as they are user dependent, users of your code).

Change the method as below

...//class preamble
public ICar myMethod(ICar myCar, String make) {
    myCar.SetMake(make);
    return myCar;
}

I would suggest you to study : DIP principle and dependency injection, code to interface.

nits.kk
  • 5,204
  • 4
  • 33
  • 55
  • Thanks for the answer. This is the only way that I could think of doing it, but was curious if there is a way to do it without dependency injection. – Tom Mar 30 '16 at 18:55
  • @RicketyRick, I would suggest you to keep the code simple. [ reference KISS principle ]. Remember simplicity is difficult to achieve, if you have it then do not try to break it or else you will break other things. Also language, OOPs perspective : Interfaces are ABSTRACT, how can you create any object from abstract or even expect JVM to crete it. Implementation depends upon our need and the code we put in the abstract method body during implementation. Its either you creating the new Concrete type objects or let the users create them and inject in your code. – nits.kk Mar 30 '16 at 19:03
  • JVM can not understand our business needs, our use cases, our requirements, onus is upon us to provide implementation for them. We do not know about future requirements, Abstract methods give us a chance to add implementation as per our specific business needs later by providing implementation to them. – nits.kk Mar 30 '16 at 19:05
  • Thanks for this. After seeing my question written down I think what i meant is: Is there a way to delay the instantiation/manipulation of the concrete class, so if you did `Car car = myMethod()`, it would perform `SetMake()` on car. But I like your suggestion of keeping it simple. How would I notify the user to inject the dependency? Is there some equivalent of `out` from C# in Java? – Tom Mar 30 '16 at 19:11
  • Car car = myMethod(); This means myMethod() has the responsibility of creating the object of Car. You can not manipulate any object until it is created, Its like eating a CAKE, you can eat once you have it. If you try to manipulate before creation then obvious NullPointerException will be thrown. Your second concern , yes you can very well modify the object later. Just create the object with new and later as per your requirement you can set its properties , like in your case you can set the make of the Car any time later as per your need, – nits.kk Mar 31 '16 at 15:17