How To Handle Composition/Aggregation and Polymorphism in Java - java

I have two abstract classes, lets call them Car's and Wheel's. I am handling different types of cars using some inheritance. So lets say there are two derivations MonsterTruckCar and ToyCar. Additionally there are different types of wheels that correspond to the Cars, say TreadedWheel's and PlasticWheel's (the mapping does not necessarily need to be one-to-one from types of cars to types of wheels). Further Car's are composed of Wheel's.
The way I thought I would be able to do this in Java is by using an attribute of Car's to be type ArrayList<Wheel>. The issue I am having is that now when I want to use polymorphism on the Wheel's I cannot because whenever I deal with a Wheel it is through an ArrayList which is not a derived class of Wheel's.
I thought I might be able to use bounded wildcards, or just a lot of switch statements to handle different combinations but I dont think either of those would be the greatest solutions. How can I handle such a structure?
Further, how do you add Wheel's to the composition/collection in Car's. That is, I need to be able to add a variable amount of concrete Wheel's to a Car, further this is going to be based off of some user input. so I would like to have a while loop in the default constructor that prompt the user if he/she wants to add another wheel and then if he/she does I add another Wheel to whatever is aggregating/collecting them in Car's.
Edit: Edited the names of the classes themselves from plural (Wheels) to singular with a 's (Wheel's) to clarify the relationship. Added the last paragraph which explains further the behavior I am looking for.

Add a generic parameter to your Car class that specified the wheel type. Here's a very basic implementation you can build on:
Edited:
Includes updated requirements, which is tricky, but doable...
public interface Wheel {
void setSize(int diameter);
}
public static abstract class Car<T extends Wheel> {
private List<T> wheels = new ArrayList<T>();
protected Car(int numberOfWheels, Class<T> wheelClass) {
while (wheels.size() < numberOfWheels) {
T wheel;
try {
wheel = wheelClass.newInstance();
} catch (Exception e) {
throw new RuntimeException(e); // simplified exception handling
}
wheel.setSize(5); // Ask user for wheel details etc
wheels.add(wheel);
}
}
public List<T> getWheels() {
return wheels;
}
}
public static class PlasticWheel implements Wheel { // or extends Wheel
#Override
public void setSize(int diameter) {
}
}
public static class ToyCar extends Car<PlasticWheel> {
public ToyCar() {
super(6, PlasticWheel.class); // or you could pass number of wheels in to this constructor
}
}
public static class TreadedWheel implements Wheel { // or extends Wheel
#Override
public void setSize(int diameter) {
}
}
public static class MonsterTruckCar extends Car<TreadedWheel> {
public MonsterTruckCar() {
super(4, TreadedWheel.class); // or you could pass number of wheels in to this constructor
}
}

Related

implement generic class of child classes

I created an Athlete class.
public class Athlete {
private final int id;
private final String name;
private final Country sourceCountry;
public Athlete(int id, String name, Country sourceCountry){
this.id = id;
this.name = name;
this.sourceCountry = sourceCountry;
}
}
then I created the following interfaces and sub classes:
public interface IJumper {
public double jump();
}
public interface IRunner {
public double run();
}
public class Runner extends Athlete implements IRunner {
public Runner(int id, String name, Country sourceCountryCode) {
super(id, name, sourceCountryCode);
}
#Override
public double run() {
return Math.random();
}
}
public class Jumper extends Athlete implements IJumper {
public Jumper(int id, String name, Country sourceCountry) {
super(id, name, sourceCountry);
}
#Override
public double jump() {
return Math.random();
}
}
in addition, I created the following RunnerJumper class to create another type of athlete that can both run and jump:
public class RunnerJumper extends Athlete implements IRunner, IJumper {
public RunnerJumper(int id, String name, Country sourceCountry) {
super(id, name, sourceCountry);
}
#Override
public double jump() {
return Math.random();
}
#Override
public double run() {
return Math.random();
}
}
now, I want to create an Team class. the team should be team of runners or jumpers (team of runners can contain Runner & RunnerJumper and team of Jumpers can contain Jumper & RunnerJumper)
so I want the team to be generic..
in addition the team class should have method like "compete" (
something like: forEach Athlete of Team:
run or jump (depends the type of athlete..)
)
how can I achieve this kind of behaviour?
I tried to create it like this:
public class Team<C extends Athlete> {}
but in this form team of runners cannot contain RunnerJumper..
I also tried to create new interface Competitor:
interface Competitor {}
and have both IRunner & IJumper extend it..
this seems good at first:
public class Team<C extends Competitor> {}
but I don't understand how I can Implement the compete functionality in this form...
It's impossible to do it the way you imagine.
Types - in Java - serve to express guarantees. Things that are 100% certain about a piece of code. If a piece of code gets a Duck, there is 100% guarantee that it is also a Bird and an Animal.
But you cannot express relations like "it's either a Duck or a Bucket". You would need both to extend the same supertype and make sure that the type is only extended by these two; in general it would require multiple inheritance and sealed types.
And you cannot express relations which mix values with types, like "if the numberOfLegs == 8, then the type is Octopus". I have no idea how to call the aparatus required for this, but the structural types in Type Script, I think, can express such constraints. I think that duck typing is a prerequisite.
Coming back to Java: if there's a set of objects which can contain Runners or RunnerJumpers, the only thing that you can guarantee in the Java's type system is that all the objects are Runners. No generics, inheritance etc. can change that.
You can use one of the multitude of patterns to achieve your business goal:
refactor the jumping / running behavior into a separate classes, both implementing Action with a single perform method. Then create an interface with a single method: getActions, called, say, a Player. Then, your Team can iterate over Players, get actions for each one and call their perform method in an inner loop. The implementation of the getAction method can even return a static list of lambdas, so that you can access all your player's attributes from inside. This pattern allows you to keep the list of possible actions open (introducing new actions will not require you to recompile or touch your Team class).
if the list of possible actions is statically known by the Team, you can use the Visitor pattern - let the Team call the player's visit method, and the player can call Team's playerJumps(Jumper j) or playerRuns(Runner r).
Or you can use other mechanisms of the language: reflection and casting (this will also make the list of possible actions static).
What you could do is you could create two Team classes, one for the runners and one for the jumpers, like so:
public interface Team {
public void compete();
}
public class TeamRunners implements Team {
private List<Runner> runners;
private List<RunnerJumper> runnerJumpers;
public Team(List<Runner> runners, List<RunnerJumper> runnerJumpers) {
this.runners = runners;
this.runnerJumpers = runnerJumpers;
}
#Override
public void compete() {
for (Runner runner : runners) {
runner.run();
}
for (RunnerJumper runnerJumper : runnerJumpers) {
runnerJumper.run();
runnerJumper.jump();
}
}
}
public class TeamJumpers implements Team {
private List<Jumper> jumpers;
private List<RunnerJumper> runnerJumpers;
public Team(List<Jumper> jumpers, List<RunnerJumper> runnerJumpers) {
this.jumpers = jumpers;
this.runnerJumpers = runnerJumpers;
}
#Override
public void compete() {
for (Jumper jumper : jumpers) {
jumper.jump();
}
for (RunnerJumper runnerJumper : runnerJumpers) {
runnerJumper.run();
runnerJumper.jump();
}
}
}

Enforcing relationships between types safely

I am building a system for writing code about people who take pictures of birds (the real system isn't actually about that, I use birds here to replace the business logic that I can't post). I'm having trouble keeping my code type safe while also enforcing all of the relationships I want and avoiding the code becoming super messy. Here's what I have.
There are three types of birds
public interface BirdType {}
public class BlueJay implements BirdType {}
public class Cardinal implements BirdType {}
public class Canary implements BirdType {}
For each type of bird, there's a type of camera specialized in taking pictures of that bird, and a special bird call which attracts birds of that type.
public interface BirdCamera<BT extends BirdType> {}
public interface BirdCall<BT extends BirdType> {}
public class BlueJayCamera implements BirdCamera<BlueJay> {}
public class CardinalCamera implements BirdCamera<Cardinal> {}
public class CanaryCamera implements BirdCamera<Canary> {}
public class BlueJayCall implements BirdCall<BlueJay> {}
public class CardinalCall implements BirdCall<Cardinal> {}
public class CanaryCall implements BirdCall<Canary> {}
These parts are combined in the Photographer interface, which enforces a relationship between the parts of a photographer for its implementers.
public interface Photographer
<BT extends BirdType,
CAM extends BirdCamera<BT>,
CAL extends BirdCall<BT>>
{
CAM getPhotographersCamera();
CAL getPhotographersBirdCall();
void examineCamera(CAM camera);
}
and it is implemented by three classes like this, one for each bird:
public class BlueJayPhotographer implements Photographer<BlueJay, BlueJayCamera, BlueJayCall> {
#Override
public BlueJayCamera getPhotographersCamera() {
//Do bluejay specific logic
return new BlueJayCamera();
}
#Override
public BlueJayCall getPhotographersBirdCall() {
//Do bluejay specific logic
return new BlueJayCall();
}
#Override
public void examineCamera(BlueJayCamera camera) {
//Do bluejay specific logic
}
}
One desirable thing about this is that it prevents future mistakes by other developers. Someone else can't later create
public class ConfusedPhotographer implements Photographer<BlueJay, CardinalCamera, CanaryCall>
because the constraints in Photographer prevent it.
When a class wants to use a photographer, they invoke the PhotographerProvider
public class PhotographerProvider {
public Photographer get(int birdCode) {
if (birdCode == 0) {
return new BlueJayPhotographer();
}
else if (birdCode == 1) {
return new CardinalPhotographer();
}
else if (birdCode == 2) {
return new CanaryPhotographer();
}
else {
throw new IllegalArgumentException("Unsupported bird code: " + birdCode);
}
}
}
One such class that needs to use photographers in many of its methods is the NationalPark, one of the core classes of my application. Here's an example NationalPark method:
public void importantMethod(PhotographerProvider photographerProvider) {
// blah blah logic goes here
int mostCommonBirdType = 1;
Photographer typicalTourist = photographerProvider.get(mostCommonBirdType);
BirdCamera cam = typicalTourist.getPhotographersCamera();
typicalTourist.examineCamera(cam);
// blah blah more logic here
}
The compiler doesn't like the last line of that method, and produces a warning:
Unchecked call to 'examineCamera(CAM)' as a member of raw type 'birdexample.Photographer'
I don't want this warning, but I can't find a way to fix it that doesn't cause an error someplace else... I'd also like to avoid making a gigantic mess where every class in my entire program has to be paramaterized with a bird type, camera, and call. How can I do this (short of just suppressing/ignoring the warning)?
Your specific example can be done without warnings as follows:
Photographer<?, ?, ?> typicalTourist = photographerProvider.get(mostCommonBirdType);
foo(typicalTourist);
<BT extends BirdType,
CAM extends BirdCamera<BT>> void foo(Photographer<BT, CAM, ?> typicalTourist) {
CAM cam = typicalTourist.getPhotographersCamera();
typicalTourist.examineCamera(cam);
}
But I would caution about your design. Honestly, anything more than 1 type variable is pretty unwieldy. 2 is tolerable for cases like maps, but 3 is just getting a bit crazy - you end up filling half your line with the type declaration. 6 (the number you say you have in the real code) is thoroughly into the territory of hating yourself, hating your colleagues, or both.
Think carefully if you really need these generics - you might save a lot of eye strain if you can get rid of them.
In addition to Andy's answer, your PhotographerProvider#get method issues a compiler warning due to its raw return type Photographer. To fix that, you can use the following:
public class PhotographerProvider {
public Photographer<?, ?, ?> get(int birdCode) {
if (birdCode == 0) {
return new BlueJayPhotographer();
} else if (birdCode == 1) {
return new CardinalPhotographer();
} else if (birdCode == 2) {
return new CanaryPhotographer();
} else {
throw new IllegalArgumentException("Unsupported bird code: " + birdCode);
}
}
}
Your method PhotographerProvider.get return a raw Photographer of unknow type of camera and birds:
public Photographer get(int birdCode) {
[...]
}
you could instead write something like
public <BT extends BirdType, CAM extends BirdCamera<BT>, CAL extends BirdCall<BT>> Photographer<BT, CAM, CALL> get(int birdCode) {
[...]
}
So you get type safety. The problem is that at least with recent version of java you could choose any BT type when calling the get method and it would be same for the compiler.
In fact all this system doesn't bring you much type safety. For example you instanciate the right type actually with an integer. And when one use a photographer he has no idea of the bird type or camera so he doen't really benefit of all of this.
The only place where it provide an added value is that a photographer of given BT type has to use a Camera and all of a given type... but you could as well do it with only BT as parametrzed type:
public interface Photographer<BT extends BirdType>
{
BirdCamera<BT> getPhotographersCamera();
BirdCall<BT> getPhotographersBirdCall();
void examineCamera(BirdCamera<BT> camera);
}
And you get method would directly get a BirdType:
public <BT extends BirdType> Photographer<BT> get(BT birdType) {
[...]
}

Is this the correct way to build class hierarchy?

Ok, so I have whole module that is in charge of generating player class in my game and after hours and hours of hard labour I came up with this hierarchy (snippets of code without making it too graphic but still providing enough to go on)
I have a base interface for Entities (which are either Player or Monsters):
public interface Entity {
public int getHP();
...
// all getters that denote all stats the Entities have in my game, nothing
else is in the interface
}
Then there is second interface extending Entity, called Classes, that contains all the setters relevant to classes:
public interface Classes extends Entity {
void setHP(int a);
... //and so on}
Finally getting to some real class, class PlayerClasses is responsible for building the classes:
public class PlayerClasses implements Classes {
private int HP, ATK, DEF, DAMAGE, DROP;
#Override
public int getHP() {
return HP;
}
#Override
public void setHP(int a) {
HP = a;
}
// this is how I build the player class
public void Rogue(){
setHP(150);
setATK(30);
setDEF(20);
setDAMAGE();
}
And finally a class which constructor is used to create the player instance that is then passed into other modules (no inheritance or direct access to any other class field or requiring any state in constructor, so win right?)
public class Player {
private int HP,ATK,DEF,DAMAGE,DROP;
private PlayerClasses c;
public Player() {
c = new PlayerClasses();
c.Rogue();
HP = c.getHP();
ATK = c.getATK();
DEF = c.getDEF();
DAMAGE = c.getDAMAGE();
DROP = c.getDrop();
}
Kind of long question, but I tried to keep it civil. Any feedback is very appreciated.
Edit: Ok to clarify why I choose to design like this, I want the player instance to be immutable object that can only be instanced with correct values, while keeping the initialization in other modules as clean as possible without any dependencies. So for example values from two different player classes cannot mix up in case it is instances in module that shows player stats and monster stats. I feel passing private HP and ATK variables in inheritance and then pulluting namespace with same variables is not a way to go for example.
I think I don't understand the reason for an immutable Player class that contains a PlayerClass. But anyways, IMO your Player class is what should inherit the Entity trait. Not the PlayerClasses object that is used as sort of template(?). Because what's the point of having a Player and I assume a similarly constructed Monster class if they aren't both Entity?
You also mix responsibilites / abstractions in an odd way. What is it that is encapsulated in the PlayerClasses and in the Player? PlayerClasses looks like it should represent the class type like "Rogue", not the actual player. And for that it shouldn't have setter methods and neither is a class type an entity.
And a factory like method that initializes a PlayerClasses object is "bad" style. You should always try to guarantee based only on class type that things are right, not have magic methods that need to be called for objects to be right (i.e. no init methods besides the constructor).
Take for example a method that takes a PlayerClasses object as parameter and you want someone else to use that code. They see that they need a reference to PlayerClass and a no-argument constructor for that class, but they can't know what all the initialization steps are. Constructor or various factory / builder patterns can guarantee exactly that.
Here's a draft of how I would have done it:
interface PlayerClass {
int getBaseHp();
int getBaseAtk();
... // more class attributes
}
// as utility so I don't have to write 20 full classes
abstract class PlayerClassBase implements PlayerClass {
private final int hp, atk, ..;
protected PlayerClassBase(int hp, int atk, ...) {
this.hp = hp;
this.atk = atk;
}
#Override
public int getBaseHp() {
return hp;
}
....
}
// short class but guaranteed that every instance of Rogue has the correct values
class Rogue {
public Rogue() {
super(40, 23, 123, ...);
}
}
// something to represent entities
interface Entity {
int getCurrentHp();
int takeDamageFrom(Entity other);
...
}
// maybe an abstract base class here as well
// represents a player that has an immutable class and it can't exist without
class Player implements Entity {
privte final PlayerClass playerClass;
private int currentHp;
...
public Player(PlayerClass playerClass) {
this.playerClass = playerClass;
currentHp = playerClass.getHp();
...
}
public int takeDamageFrom(Entity other) {
currentHp -= other.getCurrentAtk();
return currentHp;
}
}
The PlayerClass part could also be a simple enum instead of a big class hierarchy.
enum PlayerClass {
ROGUE(23, 23, 4, ...),
...
;
private final int hp;
PlayerClass(int hp, int atk, ...) {
this.hp = hp;
...
}
public int getHp() { return hp; }
...
}
That way you could statically reference PlayerClass.ROGUE and create a player like this: new Player(PlayerClass.ROGUE). Instead of currently new Player(new PlayerClass().Rogue()). Or with the big hierarchy: new Player(new Rogue())

Do I really have a car in my garage? [duplicate]

This question already has answers here:
A Base Class pointer can point to a derived class object. Why is the vice-versa not true?
(13 answers)
Closed 8 years ago.
I'm a newbie to Java programming, trying to get the hang of OOP.
So I built this abstract class:
public abstract class Vehicle{....}
and 2 subclasses:
public class Car extends Vehicle{....}
public class Boat extends Vehicle{....}
Car and Boat also hold some unique fields and methods that aren't common (don't have the same name, so I can't define an abstract method for them in Vehicle).
Now in mainClass I have setup my new Garage:
Vehicle[] myGarage= new Vehicle[10];
myGarage[0]=new Car(2,true);
myGarage[1]=new Boat(4,600);
I was very happy with polymorphism until I tried to access one of the fields that are unique to Car, such as:
boolean carIsAutomatic = myGarage[0].auto;
The compiler doesn't accept that. I worked around this issue using casting:
boolean carIsAutomatic = ((Car)myGarage[0]).auto;
That works... but it doesn't help with methods, just fields. Meaning I can't do
(Car)myGarage[0].doSomeCarStuff();
So my question is - what do I really have in my garage? I'm trying to get the intuition as well as understand what's going on "behind the scenes".
for the sake of future readers, a short summary of the answers below:
Yes, there's a Car in myGarage[]
Being a static typed language, the Java compiler will not lend access to methods/fields that are non-"Vehicle", if accessing those through a data structure based on the Vehicle super class( such as Vehicle myGarage[])
As for how to solve, there are 2 main approaches below:
Use type casting, which will ease the compiler's concerns and leave any errors in the design to run time
The fact that I need casting says the design is flawed. If I need access to non-Vehicle capabilities then I shouldn't be storing the Cars and Boats in a Vehicle based data structure. Either make all those capabilities belong to Vehicle, or use more specific (derived) type based structures
In many cases, composition and/or interfaces would be a better alternative to inheritance. Probably the subject of my next question...
Plus many other good insights down there, if one does have the time to browse through the answers.
If you need to make the difference between Car and Boat in your garage, then you should store them in distinct structures.
For instance:
public class Garage {
private List<Car> cars;
private List<Boat> boats;
}
Then you can define methods that are specific on boats or specific on cars.
Why have polymorphism then?
Let's say Vehicle is like:
public abstract class Vehicle {
protected int price;
public getPrice() { return price; }
public abstract int getPriceAfterYears(int years);
}
Every Vehicle has a price so it can be put inside the Vehicle abstract class.
Yet, the formula determining the price after n years depends on the vehicle, so it left to the implementing class to define it. For instance:
public Car extends Vehicle {
// car specific
private boolean automatic;
#Override
public getPriceAfterYears(int years) {
// losing 1000$ every year
return Math.max(0, this.price - (years * 1000));
}
}
The Boat class may have an other definition for getPriceAfterYears and specific attributes and methods.
So now back in the Garage class, you can define:
// car specific
public int numberOfAutomaticCars() {
int s = 0;
for(Car car : cars) {
if(car.isAutomatic()) {
s++;
}
}
return s;
}
public List<Vehicle> getVehicles() {
List<Vehicle> v = new ArrayList<>(); // init with sum
v.addAll(cars);
v.addAll(boats);
return v;
}
// all vehicles method
public getAveragePriceAfterYears(int years) {
List<Vehicle> vehicules = getVehicles();
int s = 0;
for(Vehicle v : vehicules) {
// call the implementation of the actual type!
s += v.getPriceAfterYears(years);
}
return s / vehicules.size();
}
The interest of polymorphism is to be able to call getPriceAfterYears on a Vehicle without caring about the implementation.
Usually, downcasting is a sign of a flawed design: do not store your vehicles all together if you need to differenciate their actual type.
Note: of course the design here can be easily improved. It is just an example to demonstrate the points.
To answer your question you can find out what exactly is in your garage you do the following:
Vehicle v = myGarage[0];
if (v instanceof Car) {
// This vehicle is a car
((Car)v).doSomeCarStuff();
} else if(v instanceof Boat){
// This vehicle is a boat
((Boat)v).doSomeBoatStuff();
}
UPDATE: As you can read from the comments below, this method is okay for simple solutions but it is not good practice, particularly if you have a huge number of vehicles in your garage. So use it only if you know the garage will stay small. If that's not the case, search for "Avoiding instanceof" on stack overflow, there are multiple ways to do it.
If you operate on the base type, you can only access public methods and fields of it.
If you want to access the extended type, but have a field of the base type where it's stored (as in your case), you first have to cast it and then you can access it:
Car car = (Car)myGarage[0];
car.doSomeCarStuff();
Or shorter without temp field:
((Car)myGarage[0]).doSomeCarStuff();
Since you are using Vehicle objects, you can only call methods from the base class on them without casting. So for your garage it may be advisable to distinguish the objects in different arrays - or better lists - an array is often not a good idea, since it's far less flexible in handling than a Collection-based class.
You defined that your garage will store vehicles, so you do not care what type of vehicles you have. The vehicles have common features like engine, wheel, behavior like moving.
The actual representation of these features might be different, but at abstract layer are the same.
You used abstract class which means that some attributes, behaviors are exactly the same by both vehicle. If you want to express that your vehicles have common abstract features then use interface like moving might mean different by car and boat. Both can get from point A to point B, but in a different way (on wheel or on water - so the implementation will be different)
So you have vehicles in the garage which behave the same way and you do not car about the specific features of them.
To answer the comment:
Interface means a contract which describes how to communicate with the outer world. In the contract you define that your vehicle can move, can be steered, but you do not describe how it will actually work, it is described in the implementation.By abstract class you might have functions where you share some implementation, but you also have function which you do not know how it will be implemented.
One example of using abstract class:
abstract class Vehicle {
protected abstract void identifyWhereIAm();
protected abstract void startEngine();
protected abstract void driveUntilIArriveHome();
protected abstract void stopEngine();
public void navigateToHome() {
identifyWhereIAm();
startEngine();
driveUntilIArriveHome();
stopEngine();
}
}
You will use the same steps by each vehicle, but the implementation of the steps will differ by vehicle type. Car might use GPS, boat might use sonar to identify where it is.
I'm a newbie to Java programming, trying to get the hang of OOP.
Just my 2 cents — I will try to make it short as many interesting things have already been said. But, in fact, there is two questions here. One about "OOP" and one about how it is implemented in Java.
First of all, yes, you have a car in your garage. So your assumptions are right. But, Java is a statically typed language. And the type system in the compiler can only "know" the type of your various object by their corresponding declaration. Not by their usage. If you have an array of Vehicle, the compiler only knows that. So it will check that you only perform operation allowed on any Vehicle. (In other words, methods and attributes visible in the Vehicle declaration).
You can explain to the compiler that "you in fact know this Vehicle is a Car", by using an explicit cast (Car). the compiler will believe you -- even if in Java there is a check at run-time, that might lead to a ClassCastException that prevent further damages if you lied (other language like C++ won't check at run-time - you have to know what you do)
Finally, if you really need, you might rely of run-time type identification (i.e.: instanceof) to check the "real" type of an object before attempting to cast it. But this is mostly considered as a bad practice in Java.
As I said, this is the Java way of implementing OOP. There is whole different class family of languages broadly known as "dynamic languages", that only check at run-time if an operation is allowed on an object or not. With those languages, you don't need to "move up" all the common methods to some (possibly abstract) base class to satisfy the type system. This is called duck typing.
You asked your butler:
Jeeves, remember my garage on the Isle of Java? Go check whether the first vehicle parked there is automatic.
and lazy Jeeves said:
but sir, what if it's a vehicle that can't be automatic or non-automatic?
That's all.
Ok, that's not really all since reality is more duck-typed than statically typed. That's why I said Jeeves is lazy.
Your problem here is at a more fundamental level: you built Vehicle in such a way that Garage needs to know more about its objects than the Vehicle interface gives away. You should try and build the Vehicle class from the Garage perspective (and in general from the perspective of everything that's going to use Vehicle): what kind of things do they need to do with their vehicles? How can I make those things possible with my methods?
For example, from your example:
bool carIsAutomatic = myGarage[0].auto;
Your garage want to know about a vehicle's engine for... reasons? Anyway, there is no need for this to be just exposed by Car. You can still expose an unimplemented isAutomatic() method in Vehicle, then implement it as return True in Boat and return this.auto in Car.
It would be even better to have a three-valued EngineType enum (HAS_NO_GEARS, HAS_GEARS_AUTO_SHIFT, HAS_GEARS_MANUAL_SHIFT), which would let your code reason on the actual characteristics of a generic Vehicle cleanly and accurately. (You'd need this distinction to handle motorbikes, anyway.)
You garage contains Vehicles, so the compiler static control view that you have a Vehicle and as .auto is a Car field you can't access it, dynamically it is a Car so the cast don't create some problem, if it will be a Boat and you try to make cast to Car will rise an exception on runtime.
This is a good place for application of the Visitor design pattern.
The beauty of this pattern is you can call unrelated code on different subclasses of a superclass without having to do weird casts everywhere or putting tons of unrelated methods into the superclass.
This works by creating a Visitor object and allowing our Vehicle class to accept() the visitor.
You can also create many types of Visitor and call unrelated code using the same methods, just a different Visitor implementation, which makes this design pattern very powerful when creating clean classes.
A demo for example:
public class VisitorDemo {
// We'll use this to mark a class visitable.
public static interface Visitable {
void accept(Visitor visitor);
}
// This is the visitor
public static interface Visitor {
void visit(Boat boat);
void visit(Car car);
}
// Abstract
public static abstract class Vehicle implements Visitable {
// NO OTHER RANDOM ABSTRACT METHODS!
}
// Concrete
public static class Car extends Vehicle {
public void doCarStuff() {
System.out.println("Doing car stuff");
}
#Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
}
// Concrete
public static class Boat extends Vehicle {
public void doBoatStuff() {
System.out.println("Doing boat stuff");
}
#Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
}
// Concrete visitor
public static class StuffVisitor implements Visitor {
#Override
public void visit(Boat boat) {
boat.doBoatStuff();
}
#Override
public void visit(Car car) {
car.doCarStuff();
}
}
public static void main(String[] args) {
// Create our garage
Vehicle[] garage = {
new Boat(),
new Car(),
new Car(),
new Boat(),
new Car()
};
// Create our visitor
Visitor visitor = new StuffVisitor();
// Visit each item in our garage in turn
for (Vehicle v : garage) {
v.accept(visitor);
}
}
}
As you can see, StuffVisitor allows you to call different code on Boat or Car depending on which implementation of visit is called. You can also create other implementations of the Visitor to call different code with the same .visit() pattern.
Also notice that using this method, there is no use of instanceof or any hacky class checking. The only duplicated code between classes is the method void accept(Visitor).
If you want to support 3 types of concrete subclasses for example, you can just add that implementation into the Visitor interface too.
I'm really just pooling the ideas of the others here (and I'm not a Java guy, so this is pseudo rather than actual) but, in this contrived example, I would abstract my car checking approach into a dedicated class, that only knows about cars and only cares about cars when looking at garages:
abstract class Vehicle {
public abstract string getDescription() ;
}
class Transmission {
public Transmission(bool isAutomatic) {
this.isAutomatic = isAutomatic;
}
private bool isAutomatic;
public bool getIsAutomatic() { return isAutomatic; }
}
class Car extends Vehicle {
#Override
public string getDescription() {
return "a car";
}
private Transmission transmission;
public Transmission getTransmission() {
return transmission;
}
}
class Boat extends Vehicle {
#Override
public string getDescription() {
return "a boat";
}
}
public enum InspectionBoolean {
FALSE, TRUE, UNSUPPORTED
}
public class CarInspector {
public bool isCar(Vehicle v) {
return (v instanceof Car);
}
public bool isAutomatic(Car car) {
Transmission t = car.getTransmission();
return t.getIsAutomatic();
}
public bool isAutomatic(Vehicle vehicle) {
if (!isCar(vehicle)) throw new UnsupportedVehicleException();
return isAutomatic((Car)vehicle);
}
public InspectionBoolean isAutomatic(Vehicle[] garage, int bay) {
if (!isCar(garage[bay])) return InspectionBoolean.UNSUPPORTED;
return isAutomatic(garage[bay])
? InspectionBoolean.TRUE
: InspectionBoolean.FALSE;
}
}
Point is, you've already decided you only care about cars when you ask about the car's transmission. So just ask the CarInspector. Thanks to the tri-state Enum, you can now know whether it is automatic or even if it is not a car.
Of course, you'll need different VehicleInspectors for each vehicle you care about. And you have just pushed the problem of which VehicleInspector to instantiate up the chain.
So instead, you might want to look at interfaces.
Abstract getTransmission out to an interface (e.g. HasTransmission). That way, you can check if a vehicle has a transmission, or write an TransmissionInspector:
abstract class Vehicle { }
class Transmission {
public Transmission(bool isAutomatic) {
this.isAutomatic = isAutomatic;
}
private bool isAutomatic;
public bool getIsAutomatic() { return isAutomatic; }
}
interface HasTransmission {
Transmission getTransmission();
}
class Car extends Vehicle, HasTransmission {
private Transmission transmission;
#Override
public Transmission getTransmission() {
return transmission;
}
}
class Bus extends Vehicle, HasTransmission {
private Transmission transmission;
#Override
public Transmission getTransmission() {
return transmission;
}
}
class Boat extends Vehicle { }
enum InspectionBoolean {
FALSE, TRUE, UNSUPPORTED
}
class TransmissionInspector {
public bool hasTransmission(Vehicle v) {
return (v instanceof HasTransmission);
}
public bool isAutomatic(HasTransmission h) {
Transmission t = h.getTransmission();
return t.getIsAutomatic();
}
public bool isAutomatic(Vehicle v) {
if (!hasTranmission(v)) throw new UnsupportedVehicleException();
return isAutomatic((HasTransmission)v);
}
public InspectionBoolean isAutomatic(Vehicle[] garage, int bay) {
if (!hasTranmission(garage[bay])) return InspectionBoolean.UNSUPPORTED;
return isAutomatic(garage[bay])
? InspectionBoolean.TRUE
: InspectionBoolean.FALSE;
}
}
Now you are saying, you only about transmission, regardless of Vehicle, so can ask the TransmissionInspector. Both the bus and the car can be inspected by the TransmissionInspector, but it can only ask about the transmission.
Now, you might decide that boolean values are not all you care about. At that point, you might prefer to use a generic Supported type, that exposes both the supported state and the value:
class Supported<T> {
private bool supported = false;
private T value;
public Supported() { }
public Supported(T value) {
this.isSupported = true;
this.value = value;
}
public bool isSupported() { return supported; }
public T getValue() {
if (!supported) throw new NotSupportedException();
return value;
}
}
Now your Inspector might be defined as:
class TransmissionInspector {
public Supported<bool> isAutomatic(Vehicle[] garage, int bay) {
if (!hasTranmission(garage[bay])) return new Supported<bool>();
return new Supported<bool>(isAutomatic(garage[bay]));
}
public Supported<int> getGearCount(Vehicle[] garage, int bay) {
if (!hasTranmission(garage[bay])) return new Supported<int>();
return new Supported<int>(getGearCount(garage[bay]));
}
}
As I've said, I'm not a Java guy, so some of the syntax above may be wrong, but the concepts should hold. Nevertheless, don't run the above anywhere important without testing it first.
If you are on Java, could use reflections to check if a function is available and execute it, too
Create Vehicle level fields that will help make each individual Vehicle more distinct.
public abstract class Vehicle {
public final boolean isCar;
public final boolean isBoat;
public Vehicle (boolean isCar, boolean isBoat) {
this.isCar = isCar;
this.isBoat = isBoat;
}
}
Set the Vehicle level fields in the inheriting class to the appropriate value.
public class Car extends Vehicle {
public Car (...) {
super(true, false);
...
}
}
public class Boat extends Vehicle {
public Boat (...) {
super(false, true);
...
}
}
Implement using the Vehicle level fields to properly decipher the vehicle type.
boolean carIsAutomatic = false;
if (myGarage[0].isCar) {
Car car = (Car) myGarage[0];
car.carMethod();
carIsAutomatic = car.auto;
}
else if (myGarage[0].isBoat) {
Boat boat = (Boat) myGarage[0];
boat.boatMethod();
}
Since your telling your compiler that everything in your garage is a Vehicle, your stuck with the Vehicle class level methods and fields. If you want to properly decipher the Vehicle type, then you should set some class level fields e.g. isCar and isBoat that will give you the programmer a better understanding of what type of Vehicle you are using.
Java is a type safe language so its best to always type check before handling data that has been casted like your Boats and Cars.
Modeling objects you want to present in a program (in order to solve some problem) is one thing, coding is another story. In your code, I think essentially it's inappropriate to model a garage using array. Arrays shouldn't be often considered as objects, although they do appear to be, usually for the sake of self-contained-ness sort of integrity of a language and providing some familiarity, but array as a type is really just a computer-specific thing, IMHO, especially in Java, where you can't extend arrays.
I understand that correctly modeling a class to represent a garage won't help answer your "cars in a garage" question; just a piece of advice.
Head back to the code. Other than getting some hang to OOP, a few questions would be helpful creating a scene hence to better understand the problem you want to resolve (assuming there is one, not just "getting some hang"):
Who or what wants to understand carIsAutomatic?
Given carIsAutomatic, who or what would perform doSomeCarStuff?
It might be some inspector, or someone who knows only how to drive auto-transmission cars, etc., but from the garage's perspective, all it knows is it holds some vehicle, therefore (in this model) it is the responsibility of this inspector or driver to tell if it's a car or a boat; at this moment, you may want to start creating another bunch of classes to represent similar types of *actor*s in the scene. Depends on the problem to be resolved, if you really have to, you can model the garage to be a super intelligent system so it behaves like a vending machine, instead of a regular garage, that has a button says "Car" and another says "Boat", so that people can push the button to get a car or a boat as they want, which in turn makes this super intelligent garage responsible for telling what (a car or a boat) should be presented to its users; to follow this improvisation, the garage may require some bookkeeping when it accepts a vehicle, someone may have to provide the information, etc., all these responsibilities go beyond a simple Main class.
Having said this much, certainly I understand all the troubles, along with the boilerplates, to code an OO program, especially when the problem it tries to resolve is very simple, but OO is indeed a feasible way to resolve many other problems. From my experience, with some input providing use cases, people start to design scenes how objects would interact with each other, categorize them into classes (as well as interfaces in Java), then use something like your Main class to bootstrap the world.

Designing an item inventory system for a game and having issues

I've been working on a little inventory system just to practice my OO programming. I am using Java 7 in Netbeans.
The player will have an inventory (ArrayList of base Item Class), all items created will be a child of that base Item class.
No items should be of type BaseItem, they will all extend off of that, so to my understanding, the BaseItem class should be abstract?
public abstract class BaseItem {
protected GoldValue itemValue;
protected String itemName;
//accessors and mutators down here
}
Child item types will also have different properties, which I was going to implement as Interfaces, such as Stackable, Consumable, etc.
The interface looks something like this
public interface Stackable {
public void stack (StackableItem bi1);
}
As you can see, I make a reference to StackableItem here, that is one of the children of BaseItem, which is also abstract and specific items will build out of.
public abstract class StackableItem extends BaseItem implements Stackable{
protected int quantity;
protected int maxStacks;
#Override
public void stack (StackableItem si)
{
if(this.getQuantity() + si.getQuantity() < maxStacks){
this.setQuantity(this.getQuantity()+si.getQuantity());
si.setQuantity(0);
}
else if(this.getQuantity() + si.getQuantity() > maxStacks){
int diff = maxStacks - this.getQuantity();
this.setQuantity(this.getQuantity() + diff);
si.setQuantity(si.getQuantity() - diff);
}
}
}
and here's an example of a specific item:
public class StackableItemExample extends StackableItem{
public StackableItemExample ()throws GoldException
{
this(new GoldValue(0,0,0), "unnamed", 1);
}
public StackableItemExample(GoldValue gv, String name, int quan) throws GoldException
{
this.itemValue = gv;
this.itemName = name;
this.quantity = quan;
this.maxStacks = 10;
this.itemValue.setGoldValue(gv.getGold()*quan, gv.getSilver()*quan, gv.getCopper()*quan);
}
}
My Inventory, being an ArrayList of BaseItem objects, is allowed to have a StackableItemExample object inserted into it no problem. The issue is, my inventory system cannot say BaseItem.stack() since the parent has no knowledge of this method.
I want to make a very easily extendable item system, that a new item can be created with extreme simplicity by implementing and extending pre-created classes and interfaces, but this is getting in my way.
No items should be of type BaseItem, they will all extend off of that, so to my understanding, the BaseItem class should be abstract?
Sounds good to me
If you want BaseItem.stack() to work, you could do at least two things:
Move stack() into your base class, and give it a default implementation of doing nothing. Then override that in your StackableItem class, or
Use instanceof to see whether the BaseItem is a StackableItem, then cast it to a StackableItem and go from there.
The second approach would look like:
BaseItem item = YourList.get(i);
if(item instanceof StackableItem){
StackableItem stackable = (StackableItem)item;
stackable.stack() /* Now works without issue */
}
Make every item Stackable - currently unstackable items should have a stack size of one. You could then get rid of the stackable abstract class and interface, putting that functionality into the base class.

Categories