Having a method accept different objects as an argument - java

First I will just put my sample code.
public class Shape {
public String colour;
public Shape(String colour) {
this.colour = colour;
}
}
public class Car {
public String colour;
public Car (String colour) {
this.colour = colour;
}
}
public class Colour {
public static String getColour(Object item) {
return item.**colour**;
}
}
I've read other questions related to this, but I just can't seem to understand. I found their original code was just too complex for me to get around. So I tried to make as simple a code as possible. Anyway, I want getColour to accept both the Shape and Car object. If I use Object like I did in my example, the "colour" in bold is considered an error. The error I get is "colour cannot be resolved or is not a field". What's wrong?
Also, I've heard a lot of "static methods are bad" etc., is this a case of it being bad? Because I find if I don't make it static, then I need to duplicate getColour methods in both the Shape and Car classes. If I should avoid static methods, then please suggest another way to do this.

What you're looking for is the concept of interfaces:
public interface Colourable {
String getColour();
void setColour(String colour);
}
You should modify the Shape and Car classes:
public class Shape implements Colourable {
public Shape(String colour) {
this.colour = colour;
}
private String colour;
public String getColour() {
return colour;
}
public void setColour(String colour) {
this.colour = colour;
}
}
(note that I've made the colour field private; this is common practice and called encapsulation)
You can then define your static method as
public static String getColour(Colourable item) {
return item.getColour();
}
And static methods are definitely not bad, though in this case the method itself is a bit superfluous, because if you already have an Colourable, you know you can call .getColour() to get its color. A bit more useful would be the method
public static boolean isRed(Colourable item) {
return "red".equals(item.getColour());
}

You can "unify" Shape and Car. There are two general approaches:
Inheritance and
Interfaces
Let's look at both.
Inheritance: When a class Porsche inherits (or, in Java syntax, extends) a class Car, you establish an "is-a" relationship. In this case: Porsche is-a Car. Now, the magic comes to work, when you use object references. You can now write something like this:
Car c = new Porsche();
Since a Porsche has everything, a Car has (plus some things on top), you can see a Porsche as a Car (each Porsche is a Car, but not each Car is a Porsche). Reading my last sentence carefully, it is obvious, that the following does not work and, in fact, produces a compile error:
Porsche p = new Car();
What you can now do is write a method, that expects a Car and pass in a Porsche (since every Porsche is a Car).
Coming back to your example. To get this working, you could define a common parent class for Shape and Car, let's call it Colourable and give it a method public Colour getColour(). Then, you could simply change your getColour(Object item) method to getColour(Colourable c).
Remeber the thing I said about the "is-a" relation? Ask yourself: is each Shape a Colourable? Is each Car a Colourable? Why should Car and Shape both be in the same bucket (Colourable)? And what to do, if Car already has a parent class, e.g. Vehicle? This solution is sub-optimal.
Interfaces: This is, where interfaces come into play. Interfaces guarantee, that certain methods are present. Instead of defining a common parent class Colourable, you could simply write Colourable as an interface, containing the method public Colour getColour(). Now Shape and Car can implements this interface. This forces you to implement this method in both classes. The beauty: you can use interfaces just like classes. Meaning your implementation of getColour(Colourable c) does not need to change.
For more details, please read the provided tutorials on Inheritance and Interfaces.

Seems like your trying to use duck typing, which isn't how Java works.
The easiest thing to do, IMHO, would be to define an interface to handle the color. E.g.:
public interface Colourful {
public String getColour();
}
public class Shape implements Colorful {
private String colour;
public Shape(String colour) {
this.colour = colour;
}
#Override
public String getColour() {
return colour;
}
}
public class Car {
private String colour;
public Car (String colour) {
this.colour = colour;
}
#Override
public String getColour() {
return colour;
}
}
Alternatively, if you don't want to change Shape and Car, you could use reflection to extract the colour field, but this is usually considered a bad idea, and you'd probably be better off not using it:
public static String getColour(Object o) {
Field colourField;
try {
colourField = o.getClass().getField("colour");
} catch (NoSuchFieldException e) {
// No such field
return null;
}
Object colourValue;
try {
colourValue = colourField.get(o);
} catch (IllegalAccessException e) {
// The field isn't public
return null;
}
if (!(colourValue instanceof String)) {
// The field isn't a String
return null;
}
return (String) colourValue;
}

The reason an error is thrown is that Object doesn't have a colour field. I wouldn't recommend it, but if you want to move forward with this design, you could make a class called ShapeCarParent (used in this case because I see no clear relationship between the two) and have both the classes inherit from that, and then change getColour, like so:
public class ShapeCarParent{
public String colour;
}
public class Car extends ShapeCarParent
public class Shape extends ShapeCarParent
public class Colour {
public static String getColour(ShapeCarParent item) {
return item.colour;
}
}
This is still pretty poor style, so you can also use an interface which you then implement in each class.
public interface ColorProperties{
public String getColour();
}
public class Car implements ColorProperites{
public String getColour() {
return colour;
}
}
public class Shape implements ColorProperites{
public String getColour() {
return colour;
}
}
Hope this helps.

Related

Instance variables inside an Abstract Class ****Eclipse malfunctioned, this question is pointless****

So in a challenge in class, we had to use a public abstract Class Cycle as the parent class and create subclasses off of it. I used Unicycle Class as an example.
My professor refuses to let me put Color color as protected. He wants it private. He said the way that I can get the privacy issue worked out was by implementing the getter and setter for color. Initially they were set as abstract Color getColor() and abstract void setColor(Color color) but I tried implementing them inside the abstract class by making them public and giving them the method body.
The test in the code is:
cycle.setColor(Color.RED);
assertEquals(Color.RED, cycle.getColor());
I continue to get the error message,
The field Cycle.color is not visible
I know it works with protected but I have to use private.
Anyone have any hints they can throw at me here? I am going nuts with all of my research and failed trials.
public abstract class Cycle
{
//Declare instance variables
private String make;
private Color color;
//Create a constructor that only contains an argument for make
public Cycle(String make)
{
this.make = make;
}
//Create a constructor that contains an argument for make and color
public Cycle(String make, Color color)
{
this.make = make;
this.color = color;
}
//Create getter and setter methods
abstract int getNumberOfWheels();
//*********Was abstract Color getColor();
public Color getColor()
{
return color;
}
//*********Was abstract void setColor(Color color);
public void setColor(Color color)
{
this.color = color;
}
final String getMake()
{
//return the make of the object
return make;
}
Unicycle Class
public class Unicycle extends Cycle
{
//Create a constructor that only holds the argument make
public Unicycle(String make)
{
//Call on the super (parent) class to create the object with arguments
super(make);
}
public Unicycle(String make, Color color)
{
super(make, color);
}
//Create a method to get the number of wheels and return 1 since a unicycle only has 1 wheel
public int getNumberOfWheels()
{
return 1;
}
}
color is not visible to sub-classes since color is private in Cycle, so having a getter/setter in the Unicycle class results in a compilation issue.
Cycle already defines a getter/setter for color, and Unicycle is-a Cyle, so there's no need to attempt to override the getter/setter in sub-classes.
Remember that any public (or protected) method defined in a base class is available to sub-classes. This is one of the benefits of using inheritance.
My professor refuses to let me put Color color as protected. He wants
it private. He said the way that I can get the privacy issue worked
out was by implementing the getter and setter for color.
In case you were wondering if he is being difficult, I can tell you that he is trying to teach you a very important concept of Object-Oriented Programming. And that is limiting the scope of your variables in this case. You don't EVER want to give direct access to the data members of a class unless they are CONSTANTS. There are a few reasons for it, one of which is in case you need to add preliminary steps in the future before returning the value (i.e. return a value from an alternate source).
Now, you have something like this:
public abstract class Parent {
private String something;
protected Parent() {
something = "N/A";
}
protected String getSomething () {
return something;
}
protected void setSomething (String something) {
this.something = something;
}
}
public class Child extends Parent {
// bad use of override
#Override
public void setSomething (String something) {
super.setSomething(something);
}
// bad use of override
#Override
public String getSomething() {
return something;
}
public static void main (String[] args) {
Child child = new Child();
child.setSomething("New value");
System.out.println(child.getSomething());
}
}
public class Unrelated {
public static void main (String[] args) {
Parent child = new Child();
child.setSomething("Foo");
System.out.println(child.getSomething());
}
}
This works.... The field in the abstract class is private. Therefore, it is blocked from direct manipulation. The child classes can override a protected method of the abstract (parent) class and make it public for unrelated classes to call freely. I included a main method in both the child class and the unrelated class to illustrate this point.
The reason why the override is bad is because it doesn't do anything... HOWEVER, protected methods are restricted to be called outside the package or by classes unrelated to the class declaring the protected method. Therefore, if the unrelated class was outside of the package, it would not be able to call these protected methods. THEREFORE, you must override them by the child classes and make them public. THAT SAID, if this is the case, you could argue that the best thing is to make the protected method public in the parent class and avoid forcing implementing classes to override protected methods just for this reason.

How do I check which subclass was passed into a constructor?

I am relatively new to Java and programming, so I apologize if this question seems stupid. I am creating a battle-game for a Java programming class -- I have a Hero class with some basic methods and a subclass Paladin that extends Hero but with its own unique methods added in. I want to have a Battleground object that passes in ANY Hero class but then check which specific subclass was passed in. How do I determine which of the Hero subclasses were passed in?
public class Hero {
private String name;
private int hitPoints;
public Hero (String name, int hitPoints) {
this.name = name;
this.hitPoints = hitPoints;
}
public String getName() { return this.name; }
public int getHitPoints() { return this.hitPoints; }
public void takeDamage(int amount) { this.hitPoints -= amount; }
}
And here is the Paladin Class
public class Paladin extends Hero {
public Hero (String name, int hitPoints) {
super(name, hitPoints);
}
public void heal(int amount) {
this.hitPoints += amount;
}
}
So in the battleground class, I have a method that attempts (incorrectly) to check if the hero passed in is a Paladin. How would I go about doing this? The if statement is a placeholder psuedo-code just to clarify what I mean.
public class Battleground {
private Hero player;
public Battleground (Hero player) {
this.player = player;
}
public void startRound() {
// HERE!!
if (player.equals(Paladin)) {
player.heal();
}
}
}
Thinking in terms of what your classes are actually modelling, it doesn't make much sense for a battleground to know that a Paladin heals themselves at the start of a round, nor for the battleground to be responsible for making sure the Paladin heals themselves.
A more sensible design would be for the game to inform the hero that the round has started, and let the particular Hero subclass control what that kind of hero does when the round starts. For example:
public class Hero {
// ...
public void onRoundStart() {
// do nothing
}
}
public class Paladin extends Hero {
// ...
#Override
public void onRoundStart() {
// your heal method takes an int as its argument
heal(10);
}
}
public class Battleground {
// ...
public void startRound() {
// let the particular Hero subclass control what happens
player.onRoundStart();
// ...
}
}
This way you don't need any if statements or instanceof checks, but also the code defining a Paladin's behaviour is in the Paladin class where it sensibly belongs. If you want to change the rules for Paladins later, it will be easier to know which class you need to edit.
This kind of refactoring is called "replace conditional with polymorphism".
Using Instanceof is Considered a Code Smell Sometimes
Using instanceof can be considered to be a code smell - which means a bad practice.
There is an alternative for you to consider.
Add the heal() method to the Hero class, but leave the implementation blank.
Put only an implementation in the Paladin class. Then, even though heal() will be called on all players, it will only do something inside Paladins.
However... if you still need to detect the class type...
Ways to Detect the class
There are multiple ways to differentiate between classes.
Instance of is one.
Another is having different constructors.
A third is having an ENUM or String field called EntityType.
In your case, I think instanceof or using a special field make the most sense.
Instanceof
if(player instanceof Paladin)
Using a Special Field
Quick Example Hero
public class Hero {
private String name;
private int hitPoints;
private int HeroType;
public Hero (String name, int hitPoints) {
this.name = name;
this.hitPoints = hitPoints;
this.heroType = BASIC_HERO;
}
public static int BASIC_HERO = 0;
public static int PALADIN_HERO = 1;
...
}
Quick Example Paladin
public class Paladin extends Hero {
public Paladin(String name, int hitPoints) {
super(name, hitPoints);
this.heroType = PALADIN_HERO;
}
}
Detecting the Type
You would have a method in both classes called getHeroType().
if(hero.getHeroType == Hero.PALADIN_HERO){
}else if(hero.getHeroType == Hero.BASIC_HERO){
}
If you want, you can use to check the class of the object:
if (player instanceof Paladin)
No question, this will work. If you don't have a lot of "special" behaviour and a limited small amount of cases, that can be a reasonable solution. But assuming that your game will end up with a lot of special handling for each subclass of Hero and probably not only in the startRound() method of your Battlefield class, your code will someday be cluttered with these instanceof checks. Same applies, if you use a specific type field within the Hero class.
In that case a better solution might be to relocate the logic into special classes and try to avoid type checks if possible or at least have a well defined place for them, if necessary.
Update: removed faulty demo implementation
You can always do player.getClass to get actuall class. As for if statements you can use instanceof operator.
So
if (player instanceof Paladin) {
((Paladin)player).heal();
}

Make several classes have the same attributes without inheritance

I'm facing a problem in Java.
I need to have several classes with the same attributes ( for example a Position and a boolean isWalkable ).
But I don't want these classes to inherit from a class Element because that would prevent me from using inheritance later.
I thought of an interface (so that the interface has the attributes), but apparently you can't have an interface inherit from a class.
There must be a way because otherwise I would have to copy/paste my attributes and there methods.
Thanks in advance for anyone who has an idea on how to overcome this problem.
For this, I would consider composition over inheritance.
public class Main {
public static void main(String[] args) {
AgentWrapper agentWrapper = new AgentWrapper(new Agent1(), false, 1);
System.out.println("isWalkable: " + agentWrapper.isWalkable());
System.out.println("position: " + agentWrapper.getPosition());
agentWrapper.getAgent().doSomething();
}
}
interface Agent {
void doSomething();
}
class Agent1 implements Agent {
public void doSomething() {
System.out.println("Agent1");
}
}
class Agent2 implements Agent {
public void doSomething() {
System.out.println("Agent1");
}
}
class AgentWrapper {
private final Agent agent; //Wrapped instance.
private final boolean isWalkable;
private final int position;
public AgentWrapper(Agent agent, boolean isWalkable, int position) {
this.agent = agent;
this.isWalkable = isWalkable;
this.position = position;
}
public Agent getAgent() {
return agent;
}
public boolean isWalkable() {
return isWalkable;
}
I suspect you might need an interface anyway, if you want to treat your objects generically - e.g. loop over all of them and draw each one. E.g. assuming your elements include "cats" and "houses":
interface Element{
public point getPosition();
public boolean isWalkable();
}
class Cat implements Element{
private Point position;
private String catBreed; // example of cat-specific data
public point getPosition() {return position;}
public boolean isWalkable() {return true;} // cats can walk
...
}
class House implements Element{
private Point position;
private String streetAddress; // example of house-specific data
public point getPosition() {return position;}
public boolean isWalkable() {return false;} // houses cannot walk
..
}
// Finally, using that common interface:
Element[] allGameObjects= {new Cat(...), new Cat(...), new House(...) };
for(Element e:allGameObjects)
draw(e, e.getPosition());
That was good enough for several system I wrote... but as other replies correctly mentioned, you might refactor to use composition - however it might not be a 100% clear-cut. I mean, I can understand if you feel Cat or House should be managed independently from their position... but what about isWalkable?
// Position is easy to separate:
class Cat { String catBreed; ... }
class House{ String streetAddress; ... }
class ElementWrapper implements Element{
Point position;
Object theObject; // could hold Cat or House
public Point getPosition() {return position;}
// however, isWalkable is a bit tricky... see remark below
}
But 'isWalkable' is tricky because in classic polymorphism you'd expect House/Cat to tell you whether they can walk (meaning they should implement an interface anyway). If you absolutely don't want (or cant) have it, you may compromise on polymorphism and do something in the lines of instanceof (if theObject is instanceof Cat then it can walk, if it's instanceof House it cannot walk, etc).
You can extend an abstract base class(containing nothing) or You can use the Decorator pattern as somebody suggested in the comments, for more information related to Decorator pattern you can read this link.

OO - Creating object using a method of no argument

I am experience some problems in understanding how the OO pattern works, My lecturer gave me the following question but I cannot solve it after thinking whole day
Scenario for my problems.
There is a class named "ShapeManager" which manages the Shape object. A class named "Shape" has two subclasses named "Circle" and "Rectangle"
The implementation of Shape class as follow
abstract public class Shape {
private String id;
private double length;
public Shape() {
}
public Shape(String id , double length) {
this.id = id;
this.length = length;
}
public void setID(String id) {
this.id = id;
}
public String getID() {
return id;
}
public void setLength(double length) {
this.length = length;
}
public double getLength() {
return length;
}
public abstract String getDetails();
}
The subclass Square as follow
public class Square extends Shape{
public Square() {
super();
}
public Square(String id , double side) {
super(id, side);
}
#Override
public String getDetails() {
return "Square => Id : "+getID() +", Side : "+ getLength() + ",Area : "+(getLength() * getLength());
}
}
The subclass Circle as follow
public class Circle extends Shape{
public Circle(){
super();
}
public Circle (String id, double radius) {
super(id, radius);
}
#Override
public String details() {
return "Circle => Id : "+getID() + ", Radius : "+ getLength() + ",Area: "+(3.14*(getLength() * getLength()));
}
}
The ShapeManager class as follow, this is not a completed class
public class ShapeManager {
public Shape createShape() {
}
public void updateLength(String id ){
}
public void deleteShape(String id) {
}
public void listShapes() {
}
}
ShapeManager have an association with Shape
ShapeManager --1------0..*--> Shape
The design of this package (All the classes above) can not be changed, implementation must be following OCP (Open-Closed Principle).
My question is: How am I suppose to complete createShape method? Without parameter, it is seemingly impossible to create an object either a Rectangle or Circle.
ShapeManager cannot create a shape if not knowing what this shape is (Square, Circle or something else). And it really doesn't know because you say the method createShare has no parameters. Either you misunderstood the question or the lecturer didn't explain it well. You should ask him/her for clarifications. If you look at the libraries of Java or any other OO language, I am pretty sure you won't find such scenario and implementation pattern as the one you gave in your example.
#croraf
You should find some other reading I think e.g. the classic book http://www.amazon.com/Design-Patterns-Elements-Reusable-Object-Oriented/dp/0201633612. The main idea of a factory is that it returns something whose type the caller doesn't know, and doesn't care about. For example, if you have a method createSocket() in some SocketFactory, this method is usually defined to return an interface or an abstract class Socket. But actually it returns new SocketImpl1() and new SocketImpl2() which are concrete classes. What the factory returns may depend on many things - a system property, the underlying OS, anything you can think of. The main idea is that the factory centralizes the creation of Socket objects at one single place. This way, if you need to make a change, you can make it just in the factory. I think this book also has some decent Java counterparts too, you may look around. Other free good sources are referenced here.
Real world examples of Factory Method pattern
I think you should have something like this, similar to how BorderFactory from java API works.
public class ShapeManager {
public Shape createCircle() {
...
return Circle;
}
public Shape createSquare() {
....
return Square;
}
...
public void updateLength(String id ){
}
public void deleteShape(String id) {
}
public void listShapes() {
}
}
You can't create shape without knowing type which shape would You like to create. You can define enumeration for types and pass the type value to the createShape(). And there You can switch between types and create the concrette shape You want.
For me, Its classic Factory pattern.
public class ShapeFactory {
public abstract Shape getShape(int shapeId);
}
public interface Const {
public static final int SHAPE_CIRCLE =1;
public static final int SHAPE_SQUARE =2;
}
public class SimpleShapeFactory extends ShapeFactory throws BadShapeException {
public Shape getShape(int shapeTypeId){
Shape shape = null;
if(shapeTypeId == Const.SHAPE_CIRCLE) {
//in future can reuse or cache objects.
shape = new Circle();
}
else if(shapeTypeId == Const.SHAPE_SQUARE) {
//in future can reuse or cache objects
shape = new Square();
}
else throw new BadShapeException("ShapeTypeId="+ shapeTypeId);
return shape;
}
}
Calling:
ShapeFactory factory = new SimpleShapeFactory();
//returns a Shape but whether it is a Circle or a
//Square is not known to the caller.
Shape s = factory.getShape(1);
s.getDetails(); // circle details called
//returns a Shape but whether it is a Circle or a
//Square is not known to the caller.
s = factory.getShape(2);
s.getDetails(); //Square details called
References:
The Open Close Principle states that the design and writing of the code should be done in a way that new functionality should be added with minimum changes in the existing code. The design should be done in a way to allow the adding of new functionality as new classes, keeping as much as possible existing code unchanged.

Refactoring abstract Java class with many child classes

I'm looking for ideas on the best way to refactor this scenario (better design, minimal effort).
Starting from the following example abstract class (actual has many more fields, methods and abstract methods) :
abstract class Car
{
private int manufactureYear;
// ... many more fields that are hard to clone
public Car(int manYear)
{
this.manufactureYear = manYear;
}
abstract public Color getColor();
abstract public int getNumCylinders();
}
There are so many child classes (say 100) that extend this class. These child classes are considered like 'specs' for the cars. Here are two examples :
class CarOne extends Car
{
private static Color COLOR = Color.Red;
private static int CYLINDERS = 4;
public CarOne(int manYear)
{
super(manYear);
}
public final Color getColor();
{
return COLOR;
}
public final int getNumCylinders()
{
return CYLINDERS;
}
}
class CarOneThousand extends Car
{
private static Color COLOR = Color.Black;
private static int CYLINDERS = 6;
public CarOneThousand(int manYear)
{
super(manYear);
}
public final Color getColor();
{
return COLOR;
}
public final int getNumCylinders()
{
return CYLINDERS;
}
}
During runtime car objects get instantiated and used:
CarOne carObject = new CarOne(2009);
carObject.getColor();
carObject.getNumCylinders();
However, after getting some external data, I discover that the car was repainted and the engine changed. The new specs for the car become:
class ModCar extends Car
{
private static Color COLOR = Color.Blue;
private static int numCylinders = 8;
public ModCar (int manYear)
{
super(manYear);
}
public final Color getColor();
{
return COLOR;
}
public final int getNumCylinders()
{
return numCylinders;
}
}
So really need to "apply" these specs to the new carObject without modifying existing fields such as manufactureDate. The problem is how to minimize the code of changes to those 100+ child classes (preferably leave them untouched) while being able to update the carObject during runtime.
N.B. I was given to work on this code so I didn't write it in this condition to begin with.
Based on the description and example, you are using inheritance inappropriately. It looks like you are creating many classes where you should be using a single class and many object instances. If this is true, you also don't need a design pattern to solve the problem. Without further clarification of the problem, this should suffice:
class Car
{
private int manufactureYear;
private Color color;
private int numCylinders;
public int getManufactureYear() { return manufactureYear; }
public void setManufactureYear(int manufactureYear) { this.manufactureYear = manufactureYear; }
public Color getColor() { return color; }
public void setColor(Color color) { this.color = color; }
public int getNumCylinders() { return numCylinders; }
public void setNumCylinders(int numCylinders) { this.numCylinders = numCylinders; }
}
Example usages:
// make a blue 6-cylinder:
Car blue6 = new Car();
blue6.setColor(BLUE);
blue6.setCylinders(6);
// make a red 4-cylinder:
Car red4 = new Car();
red4.setColor(RED);
red4.setCylinders(4);
// Uh-oh, they painted my red car!
red4.setColor(YELLOW);
If you want to minimize changes, you could use my refactored Car class from above, and then clean up the child classes so they leverage it. Something like:
class CarOne extends Car { // extends my version of Car...
private static Color COLOR = Color.Red;
private static int CYLINDERS = 4;
public CarOne() {
setColor(COLOR);
setNumCylinders(CYLINDERS );
}
// getters deleted, base class has them now
}
Since there is in fact a base class, my guess is that 99% of the code does not reference the concrete car classes (only the base class), so you should be able to change things fairly easily. Of course, hard to say without seeing the real code.
It depends on how much control you have over the code that creates these objects. I'm going to assume that this design exists for a reason that was kind of lost in the car example, but if the objects are created by calling new, then there is little you can do other than change them, although you could use the rest of this answer to suggest a more flexible way to change them.
If you can control their creation, then a factory that uses composition and returns a different kind of car object that overrides the specific parameters you care about and calls the original for the rest would allow you to affect your changes on a specific instance without changing all of the original classes. Something like:
Car carOne = CarFactory.makeCar("CarOne", 2009);
Then inside that makeCar method, you can decide whether or not to return a CarOne object, or a composite implementation:
public class CompositeCar extends Car {
private Car original;
private Color myColor;
public CompositeCar(Car original, Color myColor) {
this.original = original;
this.myColor = myColor;
}
public int getYear() { return original.getYear(); }
public Color getColor() { return myColor; }
}
I'd also recommend taking a look at the Builder Pattern if you have cases (or entire groups of classes) which have complicated construction logic, especially if some fields are required in some Cars, and different sets of fields are required in others.
Your subclasses do not provide different behavior only different data.
Hence you should not use different subclasses only different arguments.
I would suggest add a "getCar" method to your base case and use it as an a factory method.
Add the Color and Cylinder properties and load them from ... anywhere it suits your needs, it may be a database, a properties file, a mock object, from the internet, from a cosmic place ... etc.
Before:
Car car = new CarOne(2009); // Using new to get different data....
carObject.getColor();
carObject.getNumCylinders();
After:
class Car {
// Attributes added and marked as final.
private final Color color;
private final int numberCylinders;
// original
private final int manufacteredYear;
public static Car getCar( String spec, int year ) {
return new Car( year,
getColorFor( spec ) ,
getCylindersFor(spec) );
}
// Make this private so only the static method do create cars.
private Car( int year, Color color, int cylinders ) {
this.manufacturedYear = year;
this.color = color;
this.numberCylinders = cylinders;
}
// Utility methods to get values for the car spec.
private static final getColorFor( String spec ) {
// fill either from db, xml, textfile, propertie, resource bundle, or hardcode here!!!
return ....
}
private static final getCylindersFor( String spec ) {
// fill either from db, xml, textfile, propertie, resource bundle, or hardcode here!!!
return ....
}
// gettes remain the same, only they are not abstract anymore.
public Color getColor(){ return this.color; }
public int getNumCylinders(){ return this.numberCylinders; }
}
So instead of create a new car directly you would get it from the getCar method:
Car car = Car.getCar("CarOne", 2009 );
....
I wouldn't recommend you to make your car "mutable" for it may bring subtle undesired side effects ( that's why I mark the attributes as final ) . So if you need to "modify" you car, you better assign new attributes:
Car myCar = Car.getCar("XYZ", 2009 );
.... do something with car
myCar = Car.getCar("Modified", 2009 );
//-- engine and color are "modified"
Additionally you may even map the whole car so you only use one instance.
By doing this you don't have to add setters to your code. The only thing you have to do would be search and replace
Car xyz = new WhatEver( number );
For
Car xyz = Car.getCar("WhatEver", number );
And the rest of the code should run without changes.

Categories