Bridge design pattern resulting in too many generics - java

I'm currently working on something for Minecraft, and I'm using the bridge pattern so my code can used with two separate server platforms, Sponge and Bukkit, with different (but somewhat similar) API's.
I have my core code, which depends only on abstractions of common things in Minecraft that I will need later on, such as players and items, as well as abstract factory and builder classes. The code for the specific server platforms will implement the factories and builders, and provide them as dependencies to the core code.
This has been working pretty well so far, but I'm running into an issue with abstractions that depend on each other. For example, I have adapters for Minecraft inventories and items that adapt from the server platform's item/inventory type, to my own abstract item/inventory type. Item and inventory objects will need to interact with each other, and since the core code doesn't know about the implementation, I've resorted to using generics. Here's some pseudocode:
interface Item<TBase> {
TBase getBase();
}
interface Inventory<TItem extends Item<*>> {
void addItem(TItem item);
}
The Item class adapts an item from the item type used by the server platform. The addItem() method implementations will use the getBase() method to add an instance of the server platform's item to an instance of the server platform's inventory. Overall, generics provide a solution to interaction between platform specific objects.
The problem I've been running into, however, is generics getting complicated as the size of the project increases. One reason is that classes that use items/inventories will require the same generics. For example, all players have an inventory:
interface Player<TItem extends Item<*>> {
Inventory<TItem> getInventory();
void giveItem(TItem item);
}
And something that uses a player needs to have generics, and so forth.
The second issue is that there are more interactions between instances than just these two, which could mean several generic parameters for an object, and therefore more generics on all the classes that use that object.
I suppose another solution would be not using generics at all, changing getBase() to return an Object type, and blindly cast, trusting that it's the correct type (which it will be).
I've put a ton of thought into this, and this is about the best I could come up with. I'm wondering if there are any other solutions that I'm missing, or any design patterns that might help with this problem.
If having the source would help, you can find it here:
https://github.com/BenWoodworth/FastCraft/tree/master/src/main/kotlin/net/benwoodworth/fastcraft

EDITED: Well, isn't this a bridge pattern?
public interface InventoryHolder
{
public void transfer(Player toPlayer, Item item);
}
then
public class Player implements InventoryHolder
{
List<Item> items;
public Item removeItem(Item item){
return items.remove(items.indexOf(item));
}
public void addItem(Item item) {
items.add(item);
}
public void transfer(Player toPlayer, Item item)
{
toPlayer.addItem(removeItem(item));
}
}
and
public class Item {}
so
public class PlayGame
{
public static void main(String... args) {
new PlayGame().run();
}
private void run() {
Player p1 = new Player();
Player p2 = new Player();
Item item = new Item();
p1.addItem(item);
// transfer
p1.transfer(p2, item);
}
}

This is my current solution. If you see any room for improvement, by all means, share your insights. Here's some of my source code, simplified, and written in Kotlin.
dependencies:
// An abstract class, to be used by objects adapting
// native implementations. Provides an unwrap method,
// to unwrap the adapted object.
abstract class Adapter(protected val base: Any) {
#Suppress("UNCHECKED_CAST")
fun <T> unwrap() = base as T
}
// Inventory adapter, extends Adapter
abstract class InventoryAdapter(baseInventory: Any) : Adapter(baseInventory)
// Player adapter, extends Adapter
abstract class PlayerAdapter(basePlayer: Any) : Adapter(basePlayer) {
abstract fun openInventory(inventory: InventoryAdapter)
}
Sponge implementation:
// Adapts Player (from the Sponge API)
class SpongePlayerAdapter(
protected val basePlayer: Player
): PlayerAdapter(basePlayer) {
override fun openInventory(inventory: InventoryAdapter) {
// The unwrap<T>() method inferences T as Sponge's
// Inventory type, from the openInventory parameter
basePlayer.openInventory(inventory.unwrap())
}
}
The need for generics has been removed, at the cost of type safety. PlayerAdapter.openInventory() can be called by passing in an InventoryAdapter object as a parameter. If the PlayerAdapter is a SpongePlayerAdapter, and the InventoryAdapter is a SpongeInventoryAdapter, then the unwrap() method will return a Sponge Inventory, and the inventory will be opened for the player as expected.
If a BukkitInventoryAdapter object were passed in, for example, a casting exception will be thrown at runtime, since the unwrap() method will try to cast a Bukkit Inventory to a Sponge Inventory. This isn't a big issue, and shouldn't cause errors as long as dependencies are injected correctly.

The proper "solution" is to use a language that has a better type system than Java/Kotlin, unfortunately.
There's a type system feature exactly for this use case - called abstract type members or associated types or existential types (depending on the language).
This feature "hides" the generic parameter inside the concrete class, meaning that it does not bloat the generic parameter lists (the trade-off is that the type is hidden from the outside world when referred to via the base interface in the declarer/caller - it can only be accessed via the concrete class type itself).
As an example in Scala (refer to https://docs.scala-lang.org/tour/abstract-type-members.html):
// Interfaces
trait ItemBridge {
type TBase
def getBase(): TBase
}
trait InventoryBridge {
// Whoever is looking at this abstract interface, only knows that
// this is *some* class implementing `ItemBridge`.
// (hence the name "existential types")
type TItemBridge <: ItemBridge
def addItem(item: TItemBridge)
}
// Concrete implementations
class SpongeItemBridge extends ItemBridge {
type TBase = SpongeItem
...
}
class SpongeInventoryBridge extends InventoryBridge {
// ...but whenever referred to via this *concrete* class,
// `TItemBridge` is known to be exactly `SpongeItemBridge`.
// (and by extension, that `TItemBridge.TBase` is `SpongeItem`)
type TItemBridge = SpongeItemBridge
val baseInventory: List[SpongeItem] = ... // This is the "base" inventory, however it's actually represented.
// NOTE: The compiler knows `item.getBase()` returns a `SpongeItem` at this point.
def addItem(item: SpongeItemBridge) = baseInventory.add(item.getBase())
}
(The interfaces have been renamed to have a Bridge suffix to make it a bit clearer)

Related

Is it possible to have an enum where each item is associated with a class?

I'm creating a game with hundreds of abilities, so trying to leverage abstracts and generics as much as possible.
Each ability extends an abstract Ability class with universal methods like getCooldown(player), which gets a specific ability's cooldown for a player. Inheritance saves me from having to duplicate that code in every ability class.
public abstract class Ability {
public static String getCooldown() {
int cooldown;
//logic to get cooldown in milliseconds
return cooldown;
}
}
But the logic and metadata for each ability are unique and coded like such:
public class Parry extends Ability {
public static String getDescription() {
...
}
public static void castAbility() {
...
}
}
Here's my enum. I'm using an enum because abilities and their metadata are constants that are ideally available at compile time. I also don't want to store the metadata separate from the classes which have the rest of the ability logic.
public enum AbilityEnum {
BORN_READY(BornReady.class),
JUGGLER(Juggler.class),
...
PARRY(Parry.class);
public final Class<? extends Ability> cls;
AbilityEnum(Class<? extends Ability> cls) {
this.cls = cls;
}
}
In other parts of the codebase, I want to use the Enum to generically get basic info on an ability, cast a spell, etc. I want to avoid hard-coding for any specific ability because there are 200+ of them. For example, when a player opens their skill menu, I need to grab the descriptions for every ability. I'd rather not type [ability_name].getDescription() 200+ times.
for (AbilityEnum ability : AbilityEnum.values()) {
String tooltip = ability.cls.getDescription();
...
// load descriptions into menu system so players
// can hover abilities for a tooltip description
}
If I try to run this I get the error:
Cannot resolve method 'getDescription' in 'Class'
This confuses me because I bounded the generic, so why does it think it has a Class instead of an Ability? I think I'm either misusing generics or have the wrong syntax for calling methods this way. Perhaps I should be using a list or something else instead of an enum?

Java Method return concrete type from generic return type

I am trying to make an enum list, and have an abstract method defined in the enum, which each enum value implements. The problem I am facing is that the abstract class has a generic return type but I want each enum value to return a concrete type.
I'll give an example:
public enum Attributes {
name {
#Override
public void createAttribute(Person person) {
//Do some validations
//Save in some storage
}
#Override
public Name getAttribute(Person person) {
// Validations
// Retreive from storage
return new Name("test");
}
},
address {
#Override
public void createAttribute(Person person) {
//Do some validations
//Save in some storage
}
#Override
public Address getAttribute(Person person) {
// Validations
// Retreive from storage
return new Name("test");
}
}
public abstract Object getAttribute(Person person);
public abstract void createAttribute(Person person);
}
Here the issue is that I would need to do typecasting to get the concrete object which is not recommended and I don't get any type of safety. How Should I go about so that using the enum value I can get my concrete object instead of the generic one.
Now I wanna call this as,
Arrays.stream(Attributes.values()).forEach(r -> {
r.createAttribute(person);
}
final Address address = Attributes.address.getAttribute(person);
final Name name = Attributes.name.getAttribute(person);
So now whenever I need to add a new attribute I don't want to write create methods for it in the Person class every time. I just add it to enum and it gets created. But now since I have the create method in the enum, I also want the getAttribute to be present here.
Here the issue is that I would need to do typecasting to get the concrete object which is not recommended and I don't get any type of safety.
You're right. Given an enum type E with an associated enum constant C, the type of the expression E.C is E. Java provides no mechanism for naming or representing a narrower type for that expression. One of the implications is that although an enum instance can implement methods with covariant return types, the covariance is not visible outside the instance. If you depend for some purpose on the narrower return type of one of those instances' methods, then casting is your only alternative.
And you're right that such casts are not type safe. They cannot be checked by the compiler, and in practice, you as programmer can get them wrong. But the information to perform a compile-time check is not expressed by the language, so there is no scope for a workaround in the language as it is defined today.
How Should I go about so that using the enum value I can get my concrete object instead of the generic one.
You should choose an altogether different approach, not involving an enum.
If you stuck with the enum then you would have to adopt an approach that relies on the enum instances to perform any tasks that depend on their own particular characteristics. Because you ask so persistently, one possibility would be to implement a variation on double dispatch. Instead of a getObject() method, you would have something like
void acceptReceiver(AttributeReceiver r, Person p);
paired with
public interface AttributeReceiver {
default void receiveName(Name name) { /* empty */ }
default void receiveAddress(Address addr) { /* empty */ }
}
Of course, the enum instances would have to implement acceptReceiver appropriately.
You would probably want to use that a little more directly than just to retrieve attributes, but you could use it to retrieve attributes something like this:
class Example {
Name name;
Address address;
void retrieveAttributes(Person person) {
AttributeReceiver receiver = new AttributeReceiver() {
public void receiveName(Name n) { name = n; }
public void receiveAddress(Address a) { addr = a; }
};
Attributes.name.acceptReceiver(receiver, person);
Attributes.address.acceptReceiver(receiver, person);
}
}
But that's awfully roundabout when you have the alternative of using (just) methods, whether on Person or even on some non-enum utility class. I continue not to see any advantage to involving an enum here. I think your code overall would be more complex and harder to understand and maintain with enums than without.
The root issue is that you are abstracting away details that you actually care about. That's a deep design flaw. You can program your way around it, but it would be better to choose a more appropriate level of abstraction in the first place.

Abstract Class Hold Member Field or Use Getter() of Concrete Implementation?

One OOP principle I'm struggling with is Abstract Classes and their ability to hold member fields (variables).
Take for instance the following code (example 1):
public abstract class AbstractClassConstructor {
List mList;
public AbstractClassConstructor(List list) {
mList = list;
}
public Object getListRow(int row) {
return mList.get(row);
}
}
And please inspect this alternative code which provides the same functionality (example 2):
public abstract class AbstractClassGetter {
public abstract List getList();
public Object getListRow(int row) {
return getList().get(row);
}
}
I'm concerned with whether example 1 or example 2 is more maintainable, as well, I would like to follow OOP standards as close as possible.
Currently I see more coupling in example 1 than I do example 2, though I don't see many other issues. Example 2 however is more straight-forward, I like that the concrete implementation holds the private field and the AbstractClassGetter uses a method to fetch it. This feels better, but I'm struggling to apply the correct OOP principle to help me know which IS better from this perspective.
As for me, example 1 would not be ideal if mList will be used in the child class with mList's function that is specific to its type (e.g. LinkedList or ArrayList). This is because it might need to be cast to its actual type before it could get used. In this case example 2 would be better.
If there's no function of specific type needed in the child class, then example 1 would be better in term of encapsulation.
Updated
Another approach, where perhaps could be considered the middle ground is to use Generic.
public abstract class AbstractClassConstructor<T extends List> {
T mList;
public AbstractClassConstructor(T list) {
mList = list;
}
public Object getListRow(int row) {
return mList.get(row);
}
}

Code repetition vs readablility

I have multiple services (in Spring MVC) that are children of a global Service. So I need to know about the best practice (or your opinions) with multiple methods with this example:
//Domain classes
public class MyParentObject{}
public class MyObj extends MyParentObject{}
//Services
public class MyParentObjectServiceImpl implements MyParentObjectService{
#Override
public MyParentObject findObjectByProp(String prop, String objectType){
//myCode (not abstract class)
}
}
public class MyObjServiceImpl extends MyParentObjectServiceImpl implements MyObjectService{
private myObjType = "MyObj";
#Override
public MyObj findMyObjByProp(String prop){
return (MyObj) super.findObjectByProp(prop, this.myObjType);
}
}
And in this approach, I use calls like this:
MyObj foo = myObjService.findMyObjByProp(prop);
So I need to know if this approach is "better" or more apropiate that calling directly the parent method with the second parameter. E.g:
MyObj foo = (MyObj)myParentObjectService.findObjectByProp(prop, "MyObj");
..and avoiding the creation of second methods, more specific. It is important to know that the children services will be created anyway, because we have lot of code that is specific of a domain objects.
I have the idea that the first approach is better, because is more readable, but I need to support that decision with some documents, blog, or opinions to discuss this designs with my colleagues.
This looks like a tagged class hierarchy. It's difficult to comment on the value of this design in general without knowing the details. However, a slightly different approach that I would recommend is to generify your base class to gain a little bit of type safety.
In particular:
public /* abstract */ class MyParentObjectServiceImpl<T extends MyParentObject>
implements MyParentObjectService{
MyParentObjectServiceImpl(Class<T> type) { this.type = type; }
private final Class<T> type; // subclasses provide this
#Override
public T findObjectByProp(String prop){
//you can use type for object specific stuff
}
}
public class MyObjServiceImpl extends MyParentObjectServiceImpl<MyObj>
// You might not need this interface anymore
// if the only method defined is findMyObjByProp
/* implements MyObjectService */ {
MyObjServiceImpl() {
super(MyObj.class);
}
#Override
public /* final */ MyObj findMyObjByProp(String prop) {
return (MyObj) super.findObjectByProp(prop, this.myObjType);
}
}
You definitely gain in type safety (casting will only appear in the base class), you get rid of the "tags" (the strings that identify the different objects) and possibly reduce the number of classes/interfaces required to implement the whole hierarchy. I successfully used this approach several times. Note that this works best if the base class is abstract. Food for thoughts.

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.

Categories