views:

101

answers:

7

Let's say I have an object of the class Car, with like 30 variables ranging from top speed to color. I want to make a MyCar object (class MyCar extends Car) that is basically the same thing except it stores some more information.

It is not possible for me to create MyCar objects right away (since out of thousands of Car objects only a few will become MyCar objects), unless I leave the additional fields blank, but that doesn't seem too professional. And neither does creating a constructor which takes 30 arguments, or setting 30 arguments through method calls.

So, is there any way to easily inherit all the variables from a superclass object?

PS: My program is not about cars, but I figured it would be an easier example.

EDIT

Thanks for the replies. They are all helpful for my program, but not for this particular problem. Builders don't seem beneficial because these cars of mine don't have default values for their variables. Every time a car is made, all the variables are filled out (which is needed to construct a sort of "fact-sheet").

Envelopes are an interesting design, but still require me to copy all the variables in the subclass constructor. I was hoping there would be a way to circumvent this. Templates would also require me to copy all the variables one by one.

In my program the subclass acts as a sort of "wrapper class" in a search engine. The subclasses are the same as the normal cars, but they have a "ranking score". My program is designed to display regular cars, and by extending those I can easily display the subclasses and order them by score at the same time.

I have to create new objects anyway, because multiple searches can be performed on the same list of cars. So editing variables in the original cars was not an option.

Maybe there is a better solution to this problem, but for now I guess I'll have to pass the superclass object into the constructor and copy all the variables there.

Thanks for the help!

PS: I'm just thinking, perhaps I could throw all the variables into a HashMap. That way I could access them by using .get(varname), and I would only have to pass one HashMap variable into the subclass. Downside is I would have to cast a lot, since the vars are a mixture of Strings, ints, doubles etc. What do you think, is it acceptable coding style?

+1  A: 

You can add a constructor that gets a Car object and copy the values from the Car to the new MyCar.

Itay
+3  A: 

Effective Java 2nd Edition, Item 2: Consider a builder when faced with many constructor parameters

And neither does creating a constructor which takes 30 arguments, or setting 30 arguments through method calls.

If you are facing a constructor with too many parameters then you might want to have a look at: The Builder Pattern. The idea is to set only the field you want/know into the builder, without bothering with the optional ones, or ones that you'd want to use default values, then calling build() to construct the actual object. See the Java examples in that article.

Once you have setup that pattern, you can construct Cars this way (notice the clean structure):

Car car = new Car.Builder(required_param1, required_param2)
                 .color(RED) // optional params
                 .topSpeed(300)
                 .zeroToHundred(2)
                 .build();
Bakkal
FYI, the .NET equiv. is to use properties to set all optional parameters (and sometimes required -- you get IllegalStateException until you do).
Joshua
+1  A: 

It is not possible for me to create MyCar objects right away (since out of thousands of Car objects only a few will become MyCar objects),

So, you'll have lots of objects of Car type, a few of which you'd like to, at runtime, "promote" to SpecialCar type?

Do SpecialCars have exactly the same interface as Cars?

You might want to read up on Coplien's Envelope-Letter Pattern, it's a way of "changing" object type at runtime. The object doesn't really change type, of course; instead, a different "Letter" goes into the existing "Envelope". The Envelope is the handle that other code references, but method calls on the Envelope are delegated to the Letter:

 class CarEnvelope { // an envelope
    Car c ; // the letter
    CarEnvelope( Car c ) { this.c = c ; }
    int someMethod() { 
      return c.someMethod(); // delegate 
    }
    void promoteToSpecialType() {
       if( ! c.isSpecialCar() ) {
          c = new SpecialCar( c ) ;
    }
 }

 class Car {
   Car() {}
   int someMethod() { do Car stuff }
   boolean isSpecial() { return false; }
 }

 class SpecialCar extends Car {
   SpecialCar( Car c ) { /*copy c's attributes...*/ } 
   int someMethod() { do SpecialCar stuff}
   boolean isSpecial() { return true; }
 }

 CarEnvelope c = new CarEnvelope( new Car() ) ;
 // do stuff with c
 c.someMethod(); // indirectly calls Car.someMethod();
 // promote
 c.promoteToSpecialType();
 c.someMethod(); // indirectly calls SpecialCar.someMethod
tpdi
A: 

I have a feeling that what you are looking for is the notion of a template; e.g.

public class Car {
   private final int attr1;
   private final int attr2;
   ...

   public Car() {
       super();
   }

   /* copy constructor */
   public Car(Car template) {
       this.attr1 = template.attr1;
       this.attr2 = template.attr2;
       ...
   }

   /* setters and getters */
}

Then ...

Car myTemplate = new Car();
myTemplate.setAttr1(3);
myTemplate.setAttr2(11);
...

Car car1 = new Car(myTemplate);
car1.setAttr1(4);
Car car2 = new Car(myTemplate);
car1.setAttr1(5);
Stephen C
A: 

OP here.

I understand that this looks like laziness. But I already have it working by manually copying 30 variables in the constructor. Not that big of a task, I know.

The thing is, I have been taught to code with style. When I see mindless code blocks that look like copypasta my instincts tell me that there is probably a better way. So my desire to learn and strive for perfection has driven me here.

But if there really is no other way than to copy the variables (or override all the get&set methods) then I don't have to look any further.

Needless to say, all the replies in this topic have given me new insights. Thanks guys.

Rapsey
A: 

I don't get it. What's wrong with a regular inheritance?

class Car {
    private int attributeOne;
    .....
    private boolean attrbuteThirty;

    public void methodOne(){...}
    ...
    public void methodThirty(){...}
}

And then just subclass it:

 class SubCar extends Car {
     private int extraAttribute;
  }

All the 30+ attributes and methods are already inherited, that's what the extends is all about.

If what you need is to create a new object based on the data of an existing one, but you're resisting to code it! ( ¬¬ ) , then you may just create a small script to create the code for you. It's very easy. You copy/paste the generated code and you're done.

If you don't want to do it, because you don't want to duplicate the data, you may override interesting methods, and delegate the code to the original, that's what the Decorator design pattern is all about:

class SubCar extends Car {
    private Car wrapped;
    private String extraAttribute;
    public SubCar( Car original, String newAttributeOne ) {
        wrapped = original;
        this.extraAttribute = newAttributeOne;
   }

    public void someMethod() {
        wrapped.someMethod();
    }
    public String getName() { return wrapped.getName();  }
    ... and so on
    // new method 
    public String extraAttribute() { return extraAttribute; }
}

That way you won't duplicate the data, but just decorate it.

OscarRyz
A: 

We can create an interface ICar that has all the getters and setters for all the 30 columns. Car can implement ICar and can contain all the 30 fields with their corresponding getters and setters. MyCar can also implement ICar and can use composition. It exposes Car's methods as delegate methods (which can automatically be generated in an IDE like eclipse)

public interface ICar {
// getter and setter methods
}

public Car implements ICar {
 private String color;
 // getters and setters for each of the fields
}

public MyCar implements ICar {
 private Car car;
 public MyCar(Car car){
  this.car = car;
 }
 public String getColor() {
  return car.getColor();
 }
}

All consumers could then use the ICar interface for their manipulation. Will that work?

raja kolluru