258

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:

  1. Yes, there's a Car in myGarage[]
  2. 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[])
  3. As for how to solve, there are 2 main approaches below:
    1. Use type casting, which will ease the compiler's concerns and leave any errors in the design to run time
    2. 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
  4. In many cases, composition and/or interfaces would be a better alternative to inheritance. Probably the subject of my next question...
  5. Plus many other good insights down there, if one does have the time to browse through the answers.
Kevin Panko
  • 8,356
  • 19
  • 50
  • 61
T-Rex
  • 1,550
  • 2
  • 11
  • 17
  • 142
    Try ((Car)myGarage[0]).doSomeCarStuff(); – Andrew Stubbs Jul 22 '14 at 09:02
  • 5
    If you tell the compiler you have a Vehicle[], why would it expect that you actually have a Car or a Boat (or any other specific derived type). It believes you -- you have an array of Vehicles (or possibly things derived from Vehicle, but you've explicitly declared that you don't want to know about that). – Eric Towers Jul 23 '14 at 02:20
  • 1
    Which version of java do you use? `boolean carIsAutomatic = (Car)myGarage[0].auto` does not compile for me – Vitalii Fedorenko Jul 23 '14 at 02:33
  • 1
    @VitaliiFedorenko: my bad, parentheses are required here as well...`boolean carIsAutomatic = ((Car)myGarage[0]).auto` – T-Rex Jul 23 '14 at 06:00
  • 17
    More importantly...why are you stuffing `Car`s into a `Vehicle[]` if you don't want to treat them like `Vehicle`s? – cHao Jul 23 '14 at 07:32
  • 3
    @cHao asks a good question. If you *do* want to check if a `vehicle` is automatic, without first checking that it is a Car, then you could move `auto`, or better `isAuto()`, up into the `Vehicle` class, and have it always return `false` for `Boat`s. Alternatively push `isAuto()` into an interface that is implemented only by some `Vehicle`s, call it `CanBeAutomatic`. – joeytwiddle Jul 23 '14 at 08:21
  • @Eric at least it's a change from `Dog extends Animal`. – Dawood ibn Kareem Jul 23 '14 at 11:40
  • 1
    Why has this gotten so many upvotes? Don't use more abstraction than you need to! – Alec Teal Jul 27 '14 at 06:10
  • 1
    You Garage has not Cars or Boats but Vehicles... that's all garage knows about based on the definitions. Until you do something (such as a cast) to reference the Vehicle as a Car, you cannot operate on it as a Car (use any Car-specific class members). From a conceptual point of view, you have to first explicitly recognize the object as a Car before you can operate on it as one; the compiler/runtime won't do that for you implicitly. – Zenilogix Jul 27 '14 at 17:15
  • Pretty sure this belongs on http://philosophy.stackexchange.com/ ;) – jdero Jul 28 '14 at 04:07

13 Answers13

147

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.

Jean Logeart
  • 52,687
  • 11
  • 83
  • 118
  • 12
    Why have polymorphism then? Who says we should? My car at home certainly don't know how much it is worth. That would be the task of some CarMarketApp or something. What I'm trying to say price is perhaps not the best example and maybe we should use composition over enheritance. – Esben Skov Pedersen Jul 22 '14 at 10:15
  • Shouldn't it be `v.getPriceAfterYears(years);` and `s / vs.size()`? – Bergi Jul 22 '14 at 10:45
  • @Vakh: thanks for the very detailed answer. Am I to deduce then that inheritance and polymorphism are useful only if the superClass is abstract? – T-Rex Jul 22 '14 at 11:54
  • @EsbenSkovPedersen I agree that ``price`` is not the best example. It could be replaced with ``weight`` which is more naturally carried by the vehicle. I also agree that composition is to be preferred over inheritance. – Jean Logeart Jul 22 '14 at 12:04
  • 1
    @T-Rex Absolutely not! There are cases where a base class stands fine on it's own, but you might also want to inherit from it. Continuing with the `Vehicle` example, you may have a `Boat` in your garage that has all the information you need to operate your boat. But your neighbor may have a `SkiBoat`, which might also have a method for the length of ski rope, among other things. – Ogre Psalm33 Jul 22 '14 at 12:44
  • @Ogre I see. Your example is more of a code reuse thing, rather than make use of the skiBoat's "Vehicleness". – T-Rex Jul 22 '14 at 13:00
  • 30
    I don't see what's wrong with downcasting in this case. If your garage has so many bays, and each bay can be occupied by either a car or a boat, then the OP's design makes perfect sense. The design here, with separate lists of cars and boats means that you will have to update the code whenever you add a new type of vehicle (motorcycle, trailer, etc.), which is certainly worse than casting. – Gabe Jul 22 '14 at 16:45
  • 9
    The main reason for using inheritance and polymorphism: you mostly **don't** care about the difference between a car and a boat. (If this is not true, then go ahead and use separate lists) – user253751 Jul 23 '14 at 11:08
  • @Gabe: If your garage has so many bays, you might care which bays are occupied. You might want a description, or common info, about the vehicles in your bays. Whether the car parked in bay 0 has an automatic transmission, though? If you care about that, you're violating DIP, i think. – cHao Jul 23 '14 at 19:57
  • @cHao: When the owner comes to retrieve their car, I need to dispatch a valet to drive it from its parking bay to the street. Since some parking valets cannot drive a manual transmission, I need to know what kind of transmission it has so I can dispatch a valet that know how to drive that kind of car. Of course if it's a boat or trailer, I would have to do something else entirely. – Gabe Jul 23 '14 at 20:47
  • 4
    @Gabe: `public function canDrive(Vehicle vehicle) { for (Skill skill : skills) { if (vehicle.canBeDrivenWith(skill)) { return true; } } return false; }`. Now only the vehicle needs to know about its transmission. And now your valet with the pickup truck can list towing as a skill, and you *don't* have to do something else entirely -- when it comes time, they'll just use their towing skill on the trailer/boat instead of trying to start it up and drive it. – cHao Jul 24 '14 at 00:12
  • @Gabe: And the *really* fun part: Once the infrastructure is in place, it's set. When you add motorcycles to the mix, the Valet, Garage, and Vehicle classes don't need to change at all -- you simply add a new "motorcycle driving" skill type, configure things so that the valets that can drive motorcycles get it, and you're done. – cHao Jul 24 '14 at 01:31
  • You need to improve that answer with a visitor pattern, including the visitable interface which would let the Car or the Boat call the right visitor method. – Matthieu Bertin Jul 24 '14 at 13:24
85

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.

danizmax
  • 2,446
  • 2
  • 32
  • 41
  • 105
    An important note here though: If you find yourself using a lot of `instanceof` like this on a regular basis, you should really take a step back and see if you can rewrite your code in a more polymorphic way. – Keppil Jul 22 '14 at 09:14
  • 1
    @Keppil You're absolutely right, but maybe it was posted like this for demonstration purposes, to show the OP what classes he has, which would be ok. – Alexander Rühl Jul 22 '14 at 10:56
  • @Danizmax: Thanks, good to learn. Would this be good practice? – T-Rex Jul 22 '14 at 11:41
  • 2
    @T-Rex: You already have the answer from @Keppil - no it is not. Avoid `instanceof` if possible. The above code is good for demonstrating the point, but not for common use. – Alexander Rühl Jul 22 '14 at 11:49
  • 4
    In any case, I'd recommend at least an `else { throw new UnsupportedVehicleError(v); }` at the end there, unless you're *sure* that doing nothing is really the proper way to handle any and all vehicles other than cars or boats. – Ilmari Karonen Jul 22 '14 at 14:27
  • 5
    @T-Rex If cars `doSomeCarStuff` and boats `doSomeBoatStuff`, couldn't you say that `Vehicle`s all `doSomeStuff`? You know that it's a vehicle, and each type of vehicle does stuff (and probably things). You don't necessarily need to know what, the `Vehicle` can take care of that. A garage doesn't care that a car drives out and a boat is towed, it just knows there is now an empty spot. – ssube Jul 22 '14 at 17:03
  • @ssube: mmmmm... that's a good question. What you're saying, CMIIW, is that it I put all my cars, boats, bikes etc. in one data structure than I probably would need that to execute/access stuff that all of them have, meaning I can define in vehicle level. I guess that just for holding the data I should simply use seperate lists (as suggested somewhere in this thread) – T-Rex Jul 22 '14 at 18:35
  • @Keppil The problem is that you don’t want to violate SRP, so you cannot just add a gazillion methods to `Vehicle`. This is one of the weaknesses of languages with subtype polymorphism but without pattern matching. –  Jul 27 '14 at 11:21
22

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.

Alexander Rühl
  • 6,769
  • 9
  • 53
  • 96
  • For simplicity's sake, I would override the ToString() methods in each class and return the concrete type as a string then use a switch() to decide what to do with each item. – Captain Kenpachi Jul 23 '14 at 07:38
  • 3
    @JuannStrauss: I object - because toString() is not meant for that use case, the switch would be a fragile construct, since it would mean to expect every sub class to do so as well. – Alexander Rühl Jul 24 '14 at 06:20
13

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.

HamoriZ
  • 2,370
  • 18
  • 38
  • thank you. To be precise, I did not detail the full exercise I was doing here. `Vehicle` has an abstract method `steer()` which is implemented differently in `Car` and `Boat`. It works well. `Vehicle` also implements `moveable` and implements the `move()` method which works well for both `Car` and `Boat`. Another question would be for me: what is the difference between using abstraction vs. using interfaces - other than the fact that I can have a class-independant method that moves around moveable objects? – T-Rex Jul 22 '14 at 12:06
  • Oh great, I didn't know abstraction can work this way. Thanks a lot! – T-Rex Jul 22 '14 at 13:04
  • @T-Rex Some languages, like Java, limit you to a single superclass (the abstract parent class in this case), while you can implement multiple interfaces in a single child class. – Raven Dreamer Jul 22 '14 at 19:56
13

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.

MC Emperor
  • 22,334
  • 15
  • 80
  • 130
Sylvain Leroux
  • 50,096
  • 7
  • 103
  • 125
  • Actually duck typing is available in some statically typed languages also. Examples include [many languages from the ML family](http://stackoverflow.com/a/1616849/3075942) and [Go language](http://golang.org/doc/faq#implements_interface). – user Jul 26 '14 at 03:28
  • @user Obviously, this is over simplified. One might go even further in saying that some _dynamic languages_ like Groovy are JVM-based -- proving if that was needed than Java has all the necessary "stuff" to be a dynamic language. Concerning ML and Go, I won't go to a debate about at which extend _type inference_ or _structural typing_ are or not _duck typing_. The point here was only to say than _"OOP"_ and _"Java (way of implementing OOP)"_ are two different things. And if the original intuition of the OP was right, it collides with the Java OOP model. – Sylvain Leroux Jul 26 '14 at 09:59
9

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.

einpoklum
  • 118,144
  • 57
  • 340
  • 684
8

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.)

badp
  • 11,409
  • 3
  • 61
  • 89
  • A garage might want to know about a vehicle's transmission if it may need to rearrange vehicles and various vehicles may always, never, or sometimes [e.g. depending upon whether the on-duty attendant can drive stick] require a tow vehicle. Vehicles which can only be moved by tow vehicles should only go in spaces which can be reached while in tow; stick-shift vehicles should not be placed where they would "block in" automatic-transmission vehicles. I would suggest that `Vehicle` should include a method which would indicate whether it can only be moved by tow vehicle, stick-shift driver, or... – supercat Jul 22 '14 at 17:30
  • ...any attendant. Note that such ability would not necessarily depend upon the "type" of an object; a car whose engine throws a rod would still be a `Car`, but `GetRequirementsForMotion()` would report that it requires a tow vehicle. – supercat Jul 22 '14 at 17:35
  • @supercat: The garage shouldn't care about an attendant's driving abilities -- that just leads to a cascade of changes every time an attendant develops a new handicap. :P Rather, since the attendant is obviously an entity with its own properties, it should be an object. The garage should tell the attendant a vehicle has arrived, and let the attendant put the vehicle in a bay (moving other cars around if necessary). – cHao Jul 23 '14 at 22:17
  • @supercat: As for the suggestion...i'd suggest something more generic than that, actually -- a way to tag a vehicle with specific attributes and query them. You could have values representing "needs tow", "stick shift", etc. Subclasses could respond to the query by mapping attributes to properties -- which, while kinda meh, at least keeps the ugliness isolated from the caller. (Though going that route might just obviate the need for distinct `Car`, `Boat` etc types entirely, depending on what else those classes have to do.) – cHao Jul 23 '14 at 22:38
  • @supercat A silly thing for me to say, and feel free to ignore, but please look up the restrictive and non-restrictive natures of *that* and *which*. Or, short version, start using *that* exclusively unless it is obviously wrong and *which* is required. A public service announcement by yours truly! – ErikE Jul 24 '14 at 04:35
7

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.

Leonid
  • 81
  • 4
7

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.

David Xu
  • 5,555
  • 3
  • 28
  • 50
6

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.

jimbobmcgee
  • 1,561
  • 11
  • 34
  • The concept holds BUT it's screaming against every OOP principle. You need to look at how a Visitor Pattern is implemented, which would remove the need for the InspectionBoolean enumeration - which isn't a boolean. – Matthieu Bertin Jul 24 '14 at 13:23
  • @Matt - noted re the semantics of InspectionBoolean -- I just couldn't think of a better name at the time... – jimbobmcgee Jul 24 '14 at 14:18
2

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.

Jay Harris
  • 4,201
  • 17
  • 21
  • 2
    Your approach is exactly the opposite of polymorfism and something that you shouldn't unless there's no other reasonable approach. In a simple example as this class it looks fine, but in a small project of 20.000 lines it can be a real mess. On the other side, you should never have public mutable fields, because that breaks encapsulation. Finally, the Car, Boat and MotorCycle classes are not overriding their homonymous fields in Vehicule, they are only shadowing them (or they would I that really does compile). – Igor Rodriguez Jul 25 '14 at 21:28
  • @IgorRodriguez un-muted the fields as you raised a good point, but I can't possible understand how this isn't polymorphic.? a Vehicle can be a car, boat, or a motorcycle. A car is a car, a boat is a boat, and a motorcycle is a motorcycle and each one of those cannot be the other. that being said isn't that the same thing as implementing a bunch of `instanceof`s ? eg `MotorCycle instanceof Vehicle // true` `MotorCycle instanceof Car // false` – Jay Harris Jul 25 '14 at 23:01
  • The trick in polymorfism is that you shouldn't need to know when you are using one car or one boat. For example if you had a park() method in your Vehicule class, Car would implement it so that the car is stored in the Garage, while Boat would do it in a Harbour. Then, when you have a collection of Vehicules, some being Boats, some Cars and so on, every time you call park() in any of them the proper action would be performed, even if you don't know whether the type of any of them is. That is polymorfism: in the moment you need to know the type of the object there's a lack of it. – Igor Rodriguez Jul 28 '14 at 14:44
2

If you are on Java, could use reflections to check if a function is available and execute it, too

wutzebaer
  • 14,365
  • 19
  • 99
  • 170
  • 2
    Reflection should be avoid whenever possible. There are a lot of arguments against it, such as this: https://plumbr.eu/blog/six-java-features-to-stay-away-from – Igor Rodriguez Jul 25 '14 at 21:35
0

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"):

  1. Who or what wants to understand carIsAutomatic?
  2. 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.

IUSR
  • 81
  • 4