Skip instanceOf in this specific case (java) [duplicate] - java

I am attempting to implement my first Factory Design Pattern, and I'm not sure how to avoid using instanceof when adding the factory-made objects to lists. This is what I'm trying to do:
for (Blueprint bp : blueprints) {
Vehicle v = VehicleFactory.buildVehicle(bp);
allVehicles.add(v);
// Can I accomplish this without using 'instanceof'?
if (v instanceof Car) {
cars.add((Car) v);
} else if (v instanceof Boat) {
boats.add((Boat) v);
} else if (v instanceof Plane) {
planes.add((Plane) v);
}
}
From what I've read on Stack Overflow, using 'instanceof' is a code smell. Is there a better way to check the type of vehicle that was created by the factory without using 'instanceof'?
I welcome any feedback/suggestions on my implementation as I'm not even sure if I'm going about this the right way.
Full example below:
import java.util.ArrayList;
class VehicleManager {
public static void main(String[] args) {
ArrayList<Blueprint> blueprints = new ArrayList<Blueprint>();
ArrayList<Vehicle> allVehicles = new ArrayList<Vehicle>();
ArrayList<Car> cars = new ArrayList<Car>();
ArrayList<Boat> boats = new ArrayList<Boat>();
ArrayList<Plane> planes = new ArrayList<Plane>();
/*
* In my application I have to access the blueprints through an API
* b/c they have already been created and stored in a data file.
* I'm creating them here just for example.
*/
Blueprint bp0 = new Blueprint(0);
Blueprint bp1 = new Blueprint(1);
Blueprint bp2 = new Blueprint(2);
blueprints.add(bp0);
blueprints.add(bp1);
blueprints.add(bp2);
for (Blueprint bp : blueprints) {
Vehicle v = VehicleFactory.buildVehicle(bp);
allVehicles.add(v);
// Can I accomplish this without using 'instanceof'?
if (v instanceof Car) {
cars.add((Car) v);
} else if (v instanceof Boat) {
boats.add((Boat) v);
} else if (v instanceof Plane) {
planes.add((Plane) v);
}
}
System.out.println("All Vehicles:");
for (Vehicle v : allVehicles) {
System.out.println("Vehicle: " + v + ", maxSpeed: " + v.maxSpeed);
}
System.out.println("Cars:");
for (Car c : cars) {
System.out.println("Car: " + c + ", numCylinders: " + c.numCylinders);
}
System.out.println("Boats:");
for (Boat b : boats) {
System.out.println("Boat: " + b + ", numRudders: " + b.numRudders);
}
System.out.println("Planes:");
for (Plane p : planes) {
System.out.println("Plane: " + p + ", numPropellers: " + p.numPropellers);
}
}
}
class Vehicle {
double maxSpeed;
Vehicle(double maxSpeed) {
this.maxSpeed = maxSpeed;
}
}
class Car extends Vehicle {
int numCylinders;
Car(double maxSpeed, int numCylinders) {
super(maxSpeed);
this.numCylinders = numCylinders;
}
}
class Boat extends Vehicle {
int numRudders;
Boat(double maxSpeed, int numRudders) {
super(maxSpeed);
this.numRudders = numRudders;
}
}
class Plane extends Vehicle {
int numPropellers;
Plane(double maxSpeed, int numPropellers) {
super(maxSpeed);
this.numPropellers = numPropellers;
}
}
class VehicleFactory {
public static Vehicle buildVehicle(Blueprint blueprint) {
switch (blueprint.type) {
case 0:
return new Car(100.0, 4);
case 1:
return new Boat(65.0, 1);
case 2:
return new Plane(600.0, 2);
default:
return new Vehicle(0.0);
}
}
}
class Blueprint {
int type; // 0 = car; // 1 = boat; // 2 = plane;
Blueprint(int type) {
this.type = type;
}
}

You could implement the Visitor pattern.
Detailed Answer
The idea is to use polymorphism to perform the type-checking. Each subclass overrides the accept(Visitor) method, which should be declared in the superclass. When we have a situation like:
void add(Vehicle vehicle) {
//what type is vehicle??
}
We can pass an object into a method declared in Vehicle. If vehicle is of type Car, and class Car overrode the method we passed the object into, that object would now be processed within the method declared in the Car class. We use this to our advantage: creating a Visitor object and pass it to an overriden method:
abstract class Vehicle {
public abstract void accept(AddToListVisitor visitor);
}
class Car extends Vehicle {
public void accept(AddToListVisitor visitor) {
//gets handled in this class
}
}
This Visitor should be prepared to visit type Car. Any type that you want to avoid using instanceof to find the actual type of must be specified in the Visitor.
class AddToListVisitor {
public void visit(Car car) {
//now we know the type! do something...
}
public void visit(Plane plane) {
//now we know the type! do something...
}
}
Here's where the type checking happens!
When the Car receives the visitor, it should pass itself in using the this keyword. Since we are in class Car, the method visit(Car) will be invoked. Inside of our visitor, we can perform the action we want, now that we know the type of the object.
So, from the top:
You create a Visitor, which performs the actions you want. A visitor should consist of a visit method for each type of object you want to perform an action on. In this case, we are creating a visitor for vehicles:
interface VehicleVisitor {
void visit(Car car);
void visit(Plane plane);
void visit(Boat boat);
}
The action we want to perform is adding the vehicle to something. We would create an AddTransportVisitor; a visitor that manages adding transportations:
class AddTransportVisitor implements VehicleVisitor {
public void visit(Car car) {
//add to car list
}
public void visit(Plane plane) {
//add to plane list
}
public void visit(Boat boat) {
//add to boat list
}
}
Every vehicle should be able to accept vehicle visitors:
abstract class Vehicle {
public abstract void accept(VehicleVisitor visitor);
}
When a visitor is passed to a vehicle, the vehicle should invoke it's visit method, passing itself into the arguments:
class Car extends Vehicle {
public void accept(VehicleVisitor visitor) {
visitor.visit(this);
}
}
class Boat extends Vehicle {
public void accept(VehicleVisitor visitor) {
visitor.visit(this);
}
}
class Plane extends Vehicle {
public void accept(VehicleVisitor visitor) {
visitor.visit(this);
}
}
That's where the type-checking happens. The correct visit method is called, which contains the correct code to execute based on the method's parameters.
The last problem is having the VehicleVisitor interact with the lists. This is where your VehicleManager comes in: it encapsulates the lists, allowing you to add vehicles through a VehicleManager#add(Vehicle) method.
When we create the visitor, we can pass the manager to it (possibly through it's constructor), so we can perform the action we want, now that we know the object's type. The VehicleManager should contain the visitor and intercept VehicleManager#add(Vehicle) calls:
class VehicleManager {
private List<Car> carList = new ArrayList<>();
private List<Boat> boatList = new ArrayList<>();
private List<Plane> planeList = new ArrayList<>();
private AddTransportVisitor addVisitor = new AddTransportVisitor(this);
public void add(Vehicle vehicle) {
vehicle.accept(addVisitor);
}
public List<Car> getCarList() {
return carList;
}
public List<Boat> getBoatList() {
return boatList;
}
public List<Plane> getPlaneList() {
return planeList;
}
}
We can now write implementations for the AddTransportVisitor#visit methods:
class AddTransportVisitor implements VehicleVisitor {
private VehicleManager manager;
public AddTransportVisitor(VehicleManager manager) {
this.manager = manager;
}
public void visit(Car car) {
manager.getCarList().add(car);
}
public void visit(Plane plane) {
manager.getPlaneList().add(plane);
}
public void visit(Boat boat) {
manager.getBoatList().add(boat);
}
}
I highly suggest removing the getter methods and declaring overloaded add methods for each type of vehicle. This will reduce overhead from "visiting" when it's not needed, for example, manager.add(new Car()):
class VehicleManager {
private List<Car> carList = new ArrayList<>();
private List<Boat> boatList = new ArrayList<>();
private List<Plane> planeList = new ArrayList<>();
private AddTransportVisitor addVisitor = new AddTransportVisitor(this);
public void add(Vehicle vehicle) {
vehicle.accept(addVisitor);
}
public void add(Car car) {
carList.add(car);
}
public void add(Boat boat) {
boatList.add(boat);
}
public void add(Plane plane) {
planeList.add(plane);
}
public void printAllVehicles() {
//loop through vehicles, print
}
}
class AddTransportVisitor implements VehicleVisitor {
private VehicleManager manager;
public AddTransportVisitor(VehicleManager manager) {
this.manager = manager;
}
public void visit(Car car) {
manager.add(car);
}
public void visit(Plane plane) {
manager.add(plane);
}
public void visit(Boat boat) {
manager.add(boat);
}
}
public class Main {
public static void main(String[] args) {
Vehicle[] vehicles = {
new Plane(),
new Car(),
new Car(),
new Car(),
new Boat(),
new Boat()
};
VehicleManager manager = new VehicleManager();
for(Vehicle vehicle : vehicles) {
manager.add(vehicle);
}
manager.printAllVehicles();
}
}

You can add method to vehicle class to print the text. Then override the method in each specialized Car class. Then just add all the cars to the vehicle list. And loop the list to print the text.

I'm not too happy with the lists of cars, boats and planes in the first place. You have multiple examples of reality but the list isn't inherently all-inclusive--what happens when your factory starts making submarines or rockets?
Instead, how about an enum with the types car, boat and plane. You have an array of lists of vehicles.
The generic vehicle has an abstract property CatalogAs, the various vehicles actually implement this and return the proper value.

Done some restructuring of your code. Hope that works for you. Check this:
import java.util.ArrayList;
class VehicleManager {
public static void main(String[] args) {
ArrayList<ABluePrint> bluePrints = new ArrayList<ABluePrint>();
ArrayList<AVehicle> allVehicles = new ArrayList<AVehicle>();
ArrayList<ACar> cars = null;
ArrayList<ABoat> boats = null;
ArrayList<APlane> planes = null;
/*
* In my application I have to access the blueprints through an API
* b/c they have already been created and stored in a data file.
* I'm creating them here just for example.
*/
ABluePrint bp0 = new ABluePrint(0);
ABluePrint bp1 = new ABluePrint(1);
ABluePrint bp2 = new ABluePrint(2);
bluePrints.add(bp0);
bluePrints.add(bp1);
bluePrints.add(bp2);
for (ABluePrint bp : bluePrints) {
AVehicle v = AVehicleFactory.buildVehicle(bp);
allVehicles.add(v);
// Can I accomplish this without using 'instanceof'?
// dont add objects to list here, do it from constructor or in factory
/*if (v instanceof ACar) {
cars.add((ACar) v);
} else if (v instanceof ABoat) {
boats.add((ABoat) v);
} else if (v instanceof APlane) {
planes.add((APlane) v);
}*/
}
cars = ACar.getCars();
boats = ABoat.getBoats();
planes = APlane.getPlanes();
System.out.println("All Vehicles:");
for (AVehicle v : allVehicles) {
System.out.println("Vehicle: " + v + ", maxSpeed: " + v.maxSpeed);
}
System.out.println("Cars:");
for (ACar c : cars) {
System.out.println("Car: " + c + ", numCylinders: " + c.numCylinders);
}
System.out.println("Boats:");
for (ABoat b : boats) {
System.out.println("Boat: " + b + ", numRudders: " + b.numRudders);
}
System.out.println("Planes:");
for (APlane p : planes) {
System.out.println("Plane: " + p + ", numPropellers: " + p.numPropellers);
}
}
}
class AVehicle {
double maxSpeed;
AVehicle(double maxSpeed) {
this.maxSpeed = maxSpeed;
}
void add(){}
}
class ACar extends AVehicle {
static ArrayList<ACar> cars = new ArrayList<ACar>();
int numCylinders;
ACar(double maxSpeed, int numCylinders) {
super(maxSpeed);
this.numCylinders = numCylinders;
}
void add(){
cars.add(this);
}
public static ArrayList<ACar> getCars(){
return cars;
}
}
class ABoat extends AVehicle {
static ArrayList<ABoat> boats = new ArrayList<ABoat>();
int numRudders;
ABoat(double maxSpeed, int numRudders) {
super(maxSpeed);
this.numRudders = numRudders;
}
void add(){
boats.add(this);
}
public static ArrayList<ABoat> getBoats(){
return boats;
}
}
class APlane extends AVehicle {
static ArrayList<APlane> planes = new ArrayList<APlane>();
int numPropellers;
APlane(double maxSpeed, int numPropellers) {
super(maxSpeed);
this.numPropellers = numPropellers;
}
void add(){
planes.add(this);
}
public static ArrayList<APlane> getPlanes(){
return planes;
}
}
class AVehicleFactory {
public static AVehicle buildVehicle(ABluePrint blueprint) {
AVehicle vehicle;
switch (blueprint.type) {
case 0:
vehicle = new ACar(100.0, 4);
break;
case 1:
vehicle = new ABoat(65.0, 1);
break;
case 2:
vehicle = new APlane(600.0, 2);
break;
default:
vehicle = new AVehicle(0.0);
}
vehicle.add();
return vehicle;
}
}
class ABluePrint {
int type; // 0 = car; // 1 = boat; // 2 = plane;
ABluePrint(int type) {
this.type = type;
}
}
With the above code, the class will have to know about the collection to which it has to be added. This can be considered as a downside to a good design and it can be overcome using the visitor design pattern as demonstrated in the accepted answer (How to avoid 'instanceof' when implementing factory design pattern?).

I know its been a long time since this question was asked. I found http://www.nurkiewicz.com/2013/09/instanceof-operator-and-visitor-pattern.html which looks to be useful. Sharing it here in case if somebody is interested.

Had a similar issue so I used this pattern, to understand it better I created a simple UML drawing showing the sequence of things in comments (follow the numbers). I used Vince Emighs solution above.. The pattern solution is more elegant but can requires some time to truly understand. It requires one interface and one class more then the original but they are very simple.

What if AVehicle classes are out of your control? E.g. you have it from some 3rd party lib? So you have no way to add the Visitor pattern accept() method. Also you could probably dislike boilerplate code in each of the AVehicle subclass and prefer to put everything in one special class keeping your classes clean.
For some cases it could be better just to use HashMap.
In your sample just use:
Map<Class<? extends AVehicle>, List<? extends AVehicle>> lists = new HashMap<>();
lists.put(ACar.class, new ArrayList<ACar>());
lists.put(ABoat.class, new ArrayList<ABoat>());
lists.put(APlane.class, new ArrayList<APlane>());
for (ABluePrint bp : bluePrints) {
AVehicle v = AVehicleFactory.buildVehicle(bp);
allVehicles.add(v);
lists.get(v.getClass()).add(v);
}
The problem with this HashMap approach is that you have to register all possible classes including all known subclasses. Although if you have huge hierarchy and it is not needed all classes for your task you can save lots of work registering in the Map just needed ones.

Related

How to refactor to reduce complexity of this code?

I have the following code and i need to refactor it to reduce complexity and increase modularity and encapsulation. I also need to reduce the ck metrics value.
private void initialiseVehicle(String vehicleName) {
if(vehicleName.equals("Boat")) {
vehicle = new Boat("Apollo ");
}
else if(vehicleName.equals("Ship")) {
vehicle = new Ship("Cruizz");
}
else if(vehicleName.equals("Truck")) {
vehicle = new Truck("Ford F-650");
}
else if(vehicleName.equals("Motorcycle")) {
vehicle = new Motorcycle("Suzuki");
}
else if(vehicleName.equals("Bus")) {
vehicle = new Bus("Aero");
}
else if(vehicleName.equals("Car")) {
vehicle = new Car("BMW");
}
else if(vehicleName.equals("Bicycle")) {
vehicle = new Bicycle("A-bike");
}
else if(vehicleName.equals("Helicopter")) {
vehicle = new Helicopter("Eurocopter");
}
else if(vehicleName.equals("Airplane")) {
vehicle = new Airplane("BA");
}
else if(vehicleName.equals("Tram")) {
vehicle = new Tram("EdinburghTram");
}
else if(vehicleName.equals("Train")) {
vehicle = new Train("Virgin",4);
}
}
How do you refactor this code? Does switch-cases reduce any complexity?
One option could look like this:
Map<String, Function<String, Vehicle>> constructors = new HashMap<>();
constructors.put("Boat", name -> new Boat(name));
constructors.put("Ship", name -> new Ship(name));
Then the if/else code could look like
Function<String, Vehicle> constructor = constructors.get(vehicleName);
Vehicle vehicle = constructor.apply("Apollo");
Using reflection:
Vehicle vehicle;
Map<String,String> m = new HashMap<>() {{
put("Boat", "Apollo");
put("Ship", "Cruizz");
// etc
}};
private void initializeVehicle(String name) throws Exception {
vehicle = (Vehicle) Class.forName(name)
.getConstructor(String.class)
.newInstance(m.get(name));
}
But I honestly think your origina code is simple enough. Cyclomatic complexity shouldn't be a goal on itself.
This code may score very low in CK but it's not as easy to understand than the if/else chain.
So, take into consideration what are you going to use this for, the above example is very useful for libraries that doesn't known upfront the class to be created.
Here's the full running example
import java.util.*;
import java.lang.reflect.*;
import static java.lang.System.out;
class Vehicle {
String name;
public Vehicle(String aName) {
name = aName;
}
}
class Boat extends Vehicle {
public Boat(String s) {
super(s);
}
}
class Ship extends Vehicle {
public Ship(String s) {
super(s);
}
}
class Main {
Vehicle vehicle;
Map<String,String> m = new HashMap<>() {{
put("Boat", "Apollo");
put("Ship", "Cruizz");
// etc
}};
private void initializeVehicle(String name) throws Exception {
vehicle = (Vehicle) Class.forName(name).getConstructor(String.class).newInstance(m.get(name));
}
public static void main(String... args) throws Exception {
Main main = new Main();
main.initializeVehicle("Ship");
System.out.println(main.vehicle.name); // prints Cruizz as expected
}
}

OO: Does container contain bike or chair?

A container may contain bikes and chairs, both belonging to a person. I would like to check, if the container contains either bikes or chairs of said person. Is this possible without using instanceof?
public class Container {
public Map<Person, List<Item>> items = new HashMap<>();
public void add(Person p, Item item) {
items.get(p).add(item);
}
public boolean containsChair(Person owner) {
for(Item i : items.get(owner)) {
if(i instanceof Chair) {
return true;
}
}
return false;
}
public boolean containsBike(Person owner) {
for(Item i : items.get(owner)) {
if(i instanceof Bike) {
return true;
}
}
return false;
}
}
For the purpose of illustration, Item, Bike, Chair, Person are all simplest class stubs:
public class Person { public String name; }
public abstract class Item {}
public class Bike extends Item { public Wheel[] wheels;}
public class Chair extends Item { public Leg[] legs;}
public class Wheel {}
public class Leg {}
In the runner, a Person should be able to add Chairs and Bikes to its container:
import java.util.ArrayList;
public class Runner {
public static void main(String[] args) {
Container c = new Container();
Person p = new Person();
// Prevent null pointer exception
c.items.put(p, new ArrayList<>());
c.add(p, new Chair());
// True
System.out.println(c.containsChair(p));
}
}
You could add to class Item an abstract method ItemType getType(). ItemType would be an enum enumerating all possible item types.
public abstract class Item {
public abstract ItemType getType();
}
public enum ItemType {
BIKE, CHAIR;
}
Implementation of Chair:
public static class Chair extends Item {
public Leg[] legs;
#Override
public ItemType getType() {
return ItemType.CHAIR;
}
}
Then you could define a contains method to search for a the given Person if it has an item with a certain ItemType:
public boolean contains(Person owner, ItemType itemType) {
return items.get(owner).stream().anyMatch(item ->itemType.equals(item.getType()));
}
Or null-safe regarding the owners items list:
public boolean contains(Person owner, ItemType itemType) {
return Optional.ofNullable(items.get(owner))
.map(i -> i.stream().anyMatch(item -> itemType.equals(item.getType())))
.orElse(false);
}
Usage:
public static void main(String[] args) {
Container c = new Container();
Person p = new Person();
// Prevent null pointer exception
c.items.put(p, new ArrayList<>());
c.add(p, new Chair());
// True
System.out.println(c.contains(p, ItemType.CHAIR));
}
EDIT
Following this approach there is no need for instanceof checks. The usage of instanceof can be a hint indicating that the design has some flaws.
You can store Bike and Chair in two different datastructure.
public final class Container {
private final Map<Person, List<Chair>> chairs = new HashMap<>();
private final Map<Person, List<Bike>> bikes = new HashMap<>();
public void add(Person p, Chair chair) {
chairs.putIfAbsent(p, new ArrayList<Chair>());
chairs.get(p).add(chair);
}
public void add(Person p, Bike bike) {
bikes.putIfAbsent(p, new ArrayList<Bike>());
bikes.get(p).add(bike);
}
public boolean containsChair(Person owner) {
return chairs.getOrDefault(owner, Collections.emptyList()).size() > 0;
}
public boolean containsBike(Person owner) {
return bikes.getOrDefault(owner, Collections.emptyList()).size() > 0;
}
}
Note that I also made your instance fields private to hide the fact that data is stored in a Map and avoid the runner code to have the responsibility to instanciate an ArrayList if not existant. Both the class and its fields are also final to achieve a better immutability. Both encapsulation and immutability are considered good practices when doing OOP.
Usage
public static void main(String[] args) {
Container c = new Container();
Person p = new Person();
c.add(p, new Chair());
System.out.println(c.containsChair(p)); //true
System.out.println(c.containsBike(p)); //false
}
What I ended up doing was to add two methods to Item:
public boolean containsBike() {return false;}
public boolean containsChair() {return false;}
While this certainly could be optimized, the check is now done by calling the method of the object:
public boolean containsBike(Person p) {
boolean hasBike = false;
// Prevent NullPointerException
if(containsSomethingOf(p)) {
for(Item i : items.get(p)) {
if(i != null) {
if (i.containsBike()) {
hasBike = true;
}
}
}
}
return hasTrousers;
}
I think this is what is called polymorphism.

Create new Instance of Child Class

I have an array list of Enemies and each enemy kind extends enemy. Now I don't wan't every same enemy kind to share all their stats, but I base my enemy selection of another array list. So I think the way to go would be to get the object of the array list containing all the options and then changing them to new Instances of the same class. My question is, how would I do that? Or do you guys have a better approach?
For easy of understanding here's what I mean abstracted
class shop{
ArrayList<Enemy> allEnemies;
}
class generator{
ArrayList<Enemies> selectedToGenerate = based on some of allEnemies
for(Enemy x : selectedToGenerate){ // i know this wouldn't work
x = newInstanceOf(x.getNonenemyThereforeChildclassClass());
}
}
hope this explains what I mean. Appreciate your time!
You can add a Builder to your Enemy.
abstract class Enemy {
private int strength;
public Builder<Enemy> getBuilder();
public static class Builder<T extends Enemy> {
int str;
public Builder<T> copyValues(T enemy) {
str = enemey.strength;
return this;
}
public Builder<T> strength(int s) {
str = s;
return this;
}
protected void fillValues(T toFill) {
toFill.strength = str;
}
protected abstract T createInstance();
public T build() {
T result = createInstance();
fillValues(result);
return result;
}
}
}
This Builder can create instances of your Enemy and fill it with values. For subclasses, you can extend the Builder by allowing it to fill more values.
class EnemyA extends EnemyA {
private int speed;
public Builder<EnemyA> getBuilder() {
return new Builder();
}
class EnemyABuilder extends Builder<EnemyA> {
int speed;
public EnemyABuilder copyValues(EnemyA enemy) {
super.copyValues(enemy);
speed = enemy.speed;
}
public EnemyABuilder speed(int s) {
speed = s;
return this;
}
protected void fillValues(EnemyA toFill) {
super.fillValues(toFill);
toFill.speed = speed;
}
protected EnemyA createInstance() {
return new EnemyA();
}
}
}
Now, you can create copies of the enemies by using their builders:
for(Enemy x : selectedToGenerate){ // i know this wouldn't work
Builder<? extends Enemy> builder = x.getBuilder();
builer.copyValues(x);
Enemy copy = builder.build();
}
As an additional bonus, you can use the builder to quickly create different versions of the same enemy.
EnemyA.Builder base = new Builder().strength(10);
EnemyA withSpeed1 = base.speed(1).build();
EnemyA withSpeed2 = base.speed(2).build();
EnemyA withSpeed3 = base.speed(3).build();

Accessing static method of abstract class implementations

Say I have a Car abstract class:
public abstract class Car {
public enum Feature {
FAST, SEXY, RELIABLE, FUEL_EFFICIENT
};
public static List<Feature> getFeatures() {
return new ArrayList<Car.Feature>();
}
public abstract int getMaxSpeed();
}
and a number of Car implementations with various constructors like these two:
public class CarA extends Car {
private static List<Feature> features = Arrays.asList(new Feature[] {
Feature.FAST, Feature.SEXY });
private int maxSpeed;
public CarA(int year) {
maxSpeed = year > 2000 ? 240 : 220;
}
public static List<Feature> getFeatures() {
return features;
}
#Override
public int getMaxSpeed() {
return maxSpeed;
}
}
and
public class CarB extends Car {
private static List<Feature> features = Arrays
.asList(new Feature[] { Feature.FAST });
private int maxSpeed;
public CarB(int year, int modelNumber) {
if (modelNumber > 10) {
maxSpeed = year > 2010 ? 180 : 160;
} else {
maxSpeed = 100;
}
}
public static List<Feature> getFeatures() {
return features;
}
#Override
public int getMaxSpeed() {
return maxSpeed;
}
}
I want to write a car class factory that suggests a number of car instances with various configurations depending on the taste of a person:
public class CarFactory {
public static class UserPreferences {
public List<Feature> requiredFeatures;
public int minimumSpeed;
}
public List<Car> getMatchingCars(int year, UserPreferences preferences) {
List<Class<?>> candidateCarClasses = Arrays.asList(new Class<?>[] {
CarA.class, CarB.class });
List<Class<?>> carClassesWithIncorrectFeatures = new ArrayList<Class<?>>();
for (Class<?> candidateClass : candidateCarClasses) {
Class<Car> carClass = (Class<Car>) candidateClass;
// XXX how do I check carClass.getFeatures() are included in
// requiredFeatures? carClass.getMethod("getFeatures",null)???
}
candidateCarClasses.removeAll(carClassesWithIncorrectFeatures);
List<Car> cars = new ArrayList<Car>;
for (Class<?> candidateClass : candidateCarClasses) {
if (CarA.class.equals(candidateClass.getClass())) {
CarA carA = new CarA(year);
// the rest is easy...
} else if (...) {
// the rest is easy...
}
}
return cars;
}
}
My question is:
how do I access the static methods of the various car classes without having to instantiate any car object at location XXX in my code?
And if that can't be done or if I am not approaching this properly, what would be the right way to solve my problem? I.e. how can my car factory trim out first all the classes that do not have the correct features before having to instantiate the candidate classes that are left. (In the real situation I am contemplating, I have many object instances to consider for each class and the constructors are resource intensive.)
Obviously, I could move the features supported by each car implementation outside of the classes into a separate map, but it seems a cleaner approach to have all info related to a specific car instance in that implementation rather that split across multiple locations.

Java: How to design collection using a superclass

This is a practical question, but I am not sure if it has a practical answer. If you have a superclass with let's say 10 subclasses, what is the most simple way to put those 10 subclasses in a collection? Right now (this may be bad design), I have put them in a static collection field in the superclass.
The motivation for this question, however, came because I had obtained the identity of one of the fields of one of the subclasses, but I needed a reference to a different field in the same subclass.
For instance, let's say the subclass has the following fields:
public class SampleSubClass extends SampleSuperClass{
...
private Object1 o_1;
private Object2 o_2;
private Object3 o_3;
...
}
Somewhere else in the program, I have only the identity of o_2, and I wanted to get at o_3.
In theory, there might be an easier way than having to put all of the instances of SampleClass in a collection somewhere. For instance, perhaps in my dreams, there is a software language out there, where the superclass DOES carry information about its subclasses, and the superclass serves as a collection in and of itself.
But nevermind that. To me now, it seems like a good way to put the collection somewhere in the program, is to use a hashmap/hashtable, and to use it as a static member of the superclass.
Please tell me there is a better way. Is there any way to reference field A in an object by having only a reference to field B in an object?
For instance, say I have an ActionPerformed method, it has a source object that is contained in the ActionEvent object parameter. How would I find the instance of the class that owned/contained that source object? What is the best way to design this?
There is no native way to find the owner of a field given the object the field references. The JVM records the number of references pointing to each object so it can do garbage collection, but it doesn't keep track of the owners of the references.
You can store the values of all the fields in a Map which maps them to their owners:
import java.util.*;
public class Super
{
static Map<Object, Super> owners = new IdentityHashMap<Object, Super>();
// IdentityHashMap will not work with primitives due to autoboxing,
// but HashMap requires all field values to have sensible implementations
// of hashCode() and equals().
/** Gets the owner associated with a field. */
public static Object getOwner(Object field)
{
return owners.get(field);
}
/** Establishes ownership over a field. */
protected void own(Object field)
{
owners.put(field, this);
}
/** Removes an ownership, but only if this is the owner. */
protected void disown(Object field)
{
if (owners.get(field) == this) owners.remove(field);
}
/** Shorthand for disown(oldField); own(newField). */
protected <T> T change(T oldField, T newField)
{
disown(oldField);
own(newField);
return newField;
}
}
public class SubA extends Super
{
protected String s;
protected Integer i;
public SubA(String aString, Integer anInt) { setS(aString); setI(anInt); }
public void setS(String aString) { s = change(s, aString); }
public void setI(Integer anInt) { i = change(i, anInt); }
public String toString() { return "SubA(" + s + "," + i + ")"; }
}
public class SubB extends Super
{
protected Object o;
public SubB(Object anObject) { setO(anObject); }
public void setO(Object anObject) { o = change(o, anObject); }
public String toString() { return "SubB(" + o + ")"; }
}
public class Demo
{
public static void main(String[] args)
{
String s1 = "String1", s2 = "String2", s3 = "String3";
Integer i1 = 111, i2 = 222;
Object o1 = new Object(), o2 = new Object();
SubA a1 = new SubA(s1, i1), a2 = new SubA(s2, i2);
SubB b = new SubB(o1);
p("s1 owner = %s", Super.getOwner(s1)); // SubA(String1,111)
p("s2 owner = %s", Super.getOwner(s2)); // SubB(String2,222)
p("s3 owner = %s", Super.getOwner(s3)); // null
p("i1 owner = %s", Super.getOwner(i1)); // SubA(String1,111)
p("i2 owner = %s", Super.getOwner(i2)); // SubA(String2,222)
p("o1 owner = %s", Super.getOwner(o1)); // SubB(java.lang.Object#...)
p("o2 owner = %s", Super.getOwner(o2)); // null
p("s1 -> s3, o1 -> o2");
a1.setS(s3);
b.setO(o2);
p("s1 owner = %s", Super.getOwner(s1)); // null
p("s3 owner = %s", Super.getOwner(s3)); // SubA(String3,111)
p("o1 owner = %s", Super.getOwner(o1)); // null
p("o2 owner = %s", Super.getOwner(o2)); // SubB(java.lang.Object#...)
}
static void p(String fmt, Object... args)
{
System.out.format(fmt, args);
System.out.println();
}
}
Or you could make the field values themselves maintain a reference to their owner, either through inheritance or using a wrapper class:
public class OwnableObject
{
protected Object owner;
public OwnableObject(Object anOwner) { owner = anOwner; }
public Object getOwner() { return owner; }
public void setOwner(Object anOwner) { owner = anOwner; }
}
public class MyString extends OwnableObject
{
protected String str = null;
public MyString(Object anOwner) { super(anOwner); }
public String toString() { return str; }
public void set(String aString) { str = aString; }
}
public class FieldWrapper<E> extends OwnableObject
{
protected E value = null;
public FieldWrapper(Object anOwner) { super(anOwner); }
public E getValue() { return value; }
public void setValue(E aValue) { value = aValue; }
}
public class Demo
{
protected MyString s = new MyString(this);
protected FieldWrapper<Integer> i = new FieldWrapper<Integer>(this);
public void setS(String aString) { s.set(aString); }
public void setI(int anInt) { i.setValue(anInt); }
public String toString() { return "Demo(" + s + "," + i.getValue() + ")"; }
public static void main(String[] args)
{
Demo d1 = new Demo();
Demo d2 = new Demo();
MyString f1 = d1.s;
FieldWrapper<Integer> f2 = d1.i;
OwnableObject f3 = d2.s;
OwnableObject f4 = d2.i;
d1.setS("one");
d2.setS("two");
d1.setI(1000);
d2.setI(2000);
p("f1 = %s, owner = %s", f1, f1.getOwner());
p("f2 = %d, owner = %s", f2.getValue(), f2.getOwner());
p("f3 = %s, owner = %s", f3, f3.getOwner());
p("f4 = %s, owner = %s", f4, f4.getOwner());
}
static void p(String fmt, Object... args)
{
System.out.format(fmt, args);
System.out.println();
}
}
Answering your direct question: how to easily define a collection containing a given set of classes?
public class ClassA {
private final List<Class<? extends a>> knownSubclasses = Arrays.asList(ClassB.class, ClassC.class);
};
class ClassB extends ClassA {}
class ClassC extends ClassA {}
Answering your motivation: how to access a field in a subclass without declaring it for the super class?
public class SomeSuperclass {
protected Object3 getObject3() throws UnsupportedOperationException {
throw new UnsupportedOperationException();
}
}
public class SomeSubclass extends SomeSuperclass {
private final Object3 object3 = null;
#Override
protected Object3 getObject3() { return object3; }
}
Maybe recognize instances having an object3 by the use of interfaces
public interface MyClassWithObject3 { Object3 getObject3(); }
...
void someOperation(SomeSuperclass that) {
if (that instanceof MyClassWithObject3) { ... }
}
You could also use named properties
void someOperation(SomeSuperClass that) {
Object3 object3 = that.getProperty("object3");
}

Categories