How to Avoid 'Instanceof' When Implementing Factory Design Pattern

How to avoid 'instanceof' when implementing factory design pattern?

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();
}
}

Best design pattern to avoid instanceof when working with classes that cannot be modified?

There are no fundamentally different ways of solving this (at least not in Java). If you were using a language that allows for multi-dispatch, you could overload the message for the different exception types.

I would rather suggest to simply accept it. If at all I would see how the clean code rules help here, for example by making sure that each if block goes into a distinct method.

Well, there is one slightly different approach: you could potentially use a map. Keys would be the exception class, the values would be something that contains the values for your different variables that need to be assigned.

design patterns how to avoid instanceOf when using List

I don't think it's a good idea to create a separate class for each language. After all, all these classes will have the exact same methods.

I'd use a single Language class, and inside the Dish class I'll keep a Map<Locale,Description> (I'd rename the Language class to something less confusing such as Description, since it doesn't represent a language, it represents a description in some language).

Now you can have a

Description getDescription(Locale locale)

method in your Dish class, which will return the description of the dish in the language of the passed Locale.

You should prefer using standard JDK classes such as java.util.Locale instead of custom classes when possible.

After considering the comments, and agreeing to some of them, I suggest removing the Map to the Description class.

class Dish 
{
Description description = new Description ();

void addDescription(Locale locale, String text)
{
description.addText(locale,text);
}

String getDescription(Locale locale)
{
return description.getText(locale);
}
}

class Description
{
Map<Locale,String> descriptions = new HashMap<>();

public void addText(Locale locale,String text)
{
descriptions.put(locale,text);
}

public void getText(Locale locale)
{
return descriptions.get(locale);
}
}

You should also note that searching the language specific description in a Map is more efficient than searching for it in a List (O(1) lookup time in a HashMap vs. O(n) lookup time in a List).

How to avoid using instanceof in MVC Architecture

That's actually a very common problem to solve when you aim at segregating concerns. For instance, if rendering wasn't segregated from the model then you'd have a PowerUp.render() method so they can render themselves and call it a day.

However, you'd then have another problem where all sorts of concerns would end up in a single class. It's a trade-off, you either implement the operations directly on the objects or you extract those behaviors, but then have to perform type matching in some way.

The abstract factory can be interesting here as it reduces the number of type-based decisions you will have to make, but should you need to make other type-based decisions (e.g. different power-up sounds), you will have to type-match again and there's no way out of it.

That being said, you could implement a reusable type-safe mechanism for type-matching using the Visitor Pattern.

e.g. (access modifiers left out for brevity)

interface PowerUpVisitor {
visit(Invincibility powerUp);
visit(Freeze powerUp);
visit(Fright powerUp);
}

interface PowerUp {
accept(PowerUpVisitor visitor);
...
}

class Freeze implements PowerUp {
accept(PowerUpVisitor visitor) { visitor.visit(this); }
}

class PlayPowerUpSound implements PowerUpVisitor {
visit(Invincibility powerUp) { playInvicibilitySound(); }
...
}

class RenderPowerUp implements PowerUpVisitor {
visit(Invincibility powerUp) { renderInvisibility(); }
...
}

//In practice you would most likely reuse the same visitor instances
somePowerUp.accept(new PlayPowerUpSound()); //to play sound
somePowerUp.accept(new RenderPowerUp()); //to render

The main advantage of this pattern is that now the compiler will tell you if you've forgot to handle a specific type of power-up, unlike the instanceof checks.

With dynamic type-based resolution like in the other proposed abstract factory solution, you'd have to implement runtime-based validation using reflection to make sure a factory exists for all types.

The Visitor Pattern often comes to mind naturally for hierarchical structures like abstract syntax trees, but it's just as useful here.

There's also other ways if you agree to make the segregation less strict. For instance, you could introduce a specialized interface for the various behaviors a PowerUp may have, such as IPlaySound, IHaveAView, etc. and implement these operations in the powerups directly. The boundaries are now drawn solely by interfaces, but they still exist.

Finally, you could also ask the powerups for their respective renderer or sound player instead of having the operation carried out by the object directly. I think I prefer the visitor here, but there's many ways to skin a cat depending on the complexity you expect, etc. It's all about trade-offs!

Possible design pattern instead of instanceof?

Your RuleDTO class should have a method called setStuff() or something similar.

Then you override it in AssignmentRuleDTO and in EvaluationRuleDTO to set the relevant fields.

This way your ObjectConversionHelper can just call

ruleDTO.setStuff();


Related Topics



Leave a reply



Submit