j2emanue j2emanue - 1 month ago 7
Java Question

Java - Visitor pattern for adding methods

So i created a simple visitor pattern for liquids. Such as Milk,juice and liquor.

a Milk class can look like this:

public class Milk implements Visitable{

public float tax=0;

@Override
public int price() {
return 4;
}

@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
}


//and likewise for juice and liquor

and then we can have a visitor which looks like this to do the work of calculating taxes :

public class TaxVisitor implements Visitor {

double taxPerentLiquor=.18;
double taxPerentMilk=.15;
double taxPerentJuice=.10;


@Override
public void visit(Liquor liquor) {

int price =liquor.price();
liquor.setTax((float) (price*taxPerentLiquor));
}

@Override
public void visit(Milk milk) {
float price =milk.price();
milk.setTax((float) (price*taxPerentMilk));


}

@Override
public void visit(Juice juice) {

int price =juice.price();
juice.setTax((float) (price*taxPerentJuice));

}


}

and when we are using it we would do this:

Visitor taxVisitor = new TaxVisitor();

Milk milk = new Milk();
Juice juice = new Juice();

milk.accept(taxVisitor);
juice.accept(taxVisitor);


and a "visitor" would calculate the tax for each liquid for me. and i see the benefit that i do not have to modify the collection of objects themselves when i want to add a new calculation. But my trouble comes when i want to add a new method. Following open closed principle i should not be adding new methods to the milk class for example. But let us imagine i want to add functionality to know what color the liquid is. So i'd like to extend the milk object to have a method called "getColor()" which would return "#FFFFFF". This seems like i would need a decorator pattern to add this functionality if i want to follow SOLID open closed principle. Is there a way to do this with visitor pattern ?

Answer

Add the function, you aren't violating O/C

You won't violate O/C by adding a new function, as long as that function does not affect any existing code. You'll be perfectly fine adding a getColor() to your liquids.

O/C is about preventing modification of existing code

The purpose of O/C is to avoid contract violations. When a developer writes software, they'll specify exactly how the software should and should not work. This is the contract.

When writing code that other developers depend on, you cannot be sure what contracts those developers have set in place. All you know about is the contract you defined for your code. Developers trust that you will not modify your contract in a way that modifies theirs.

Since you cannot be sure whether changing your contract will affect other developers' contracts, any code of yours that other developers use must be "CLOSED for modification", or you risk contract violations.

O/C doesn't prevent you from scaling up

Adding code that has no effect on existing code doesn't carry risk of interfering with other developers' contracts.

Let's say a company was using your liquid classes before getColor existed. If you released a new version that contained getColor, the company would have to update their software to use that new function. Until they've updated their software to use that function, it has no affect on their software. This is the idea behind "OPEN for extension".

Comments