I've been trying to figure out if theres a way to pass a string to a factory or constructor and create the correct object without having to map the string to an object, or without having a bunch of if/else statements or switch statements.
Keep in mind, this is a simple example so I can apply what I learn to more complicated situations in web apps, etc.
let's take a simple calculator app, written in JAVA, as an example
assuming this is command line, and a person can pass in 3 values
- first number
- math operation (+ , - , / , x)
- second number
and we have an interface
public interface ArithmeticOperation {
public double performMathOperation(double firstNum, double secondNum);
}
with 4 classes that implement it
public class AdditionOperation implements ArithmeticOperation {
public double performMathOperation(double firstNum, double secondNum) {
return firstNum + secondNum;
}
}
// public class Subtraction operation returns firstNum - secondNum
// etc...
and we have our actual Calculator class and UserInput class
public class UserInput {
public UserInput(double firstNum, double secondNum, String operation) {
this.firstNum = firstNum;
// etc...
}
}
public class Calculator {
public UserInput getInput() {
// get user input, and return it as a UserInput object
// return a UserInput object
}
public performOperation() {
UserInput uInput = getInput();
double answer = ArithmeticOperationFactory
.getSpecificOperation(uInput.operation)
.performMathOperation(uInput.firstNum, uInput.secondNum);
// send answer back to user
}
}
finally, the place where the question mostly revolves around, the factory
public class ArithmeticOperationFactory {
public static ArithmeticOperation getSpecificOperation(String operation) {
// what possibilities are here?
// I don't want a map that maps strings to objects
// I don't want if/else or switch statements
// is there another way?
}
}
also, if theres a better way to architect a system like this or a design pattern that can be applied, please share. I'm really trying to learn some good object oriented design
There is a different way. I'm not sure it's better.
We have to go back to the interface and add another method so that the class can identify the operator.
public interface ArithmeticOperation {
public boolean isOperator(String operator);
public double performMathOperation(double firstNum, double secondNum);
}
We code the concrete methods like this:
public class AdditionOperation implements ArithmeticOperation {
#Override
public boolean isOperator(String operator) {
return operator.equals("add");
}
#Override
public double performMathOperation(double firstNum, double secondNum) {
return firstNum + secondNum;
}
}
We put all of the ArithmeticOperation classes in a List
List<ArithmeticOperation> operations = new ArrayList<>();
operations.add(new AdditionOperation());
...
Finally, we perform the operation like this.
double answer = 0D;
for (ArithmeticOperation operation : operations) {
if (operation.isOperator(currentOperator) {
answer = operation.performMathOperation(firstNum, secondNum);
break;
}
}
I would implement it using switch case. This is Factory Design Pattern.
class ArithmeticOperationFactory {
public static ArithmeticOperation getSpecificOperation(String operation) {
switch (operation) {
case "ADD":
return new AdditionOperation();
case "SUBTRACT":
return new SubtractOperation();
// You can define the rest of the operation here.
default:
throw new UnsupportedOperationException("OPeratino is not supported: " + operation);
}
}
}
You can also define Enum for each operation and use them in switch-case.
There is no method which is much better than solutions you have seen before. You can only make it slightly more elegant. In essence you can have:
Bunch of if/else/switch (probably least elegant but fast)
if("typeAsString").equals("operation"){
return new SomeType()
}
Map
Map<String, Class<? extends YourType> map = new HashMap<>();
You can make it bit better with dependency injection or you can make each subclass to add its own entry in this map. I'd favor keeping configuration away from factory class and moving it to subclasses.
Kind of chain of responsibility
You have to create Collection of all your subtypes. Each subtype has to have method like isItCorrectSubtype(). Client class has to iterate through whole collection and check which implementation is correct
#Autowired
List<InterfaceOfYourTypes> allSubtypes;
..
public void doStuff(){
for(InterfaceOfYourTypes subtype: allSubtypes){
if(subtype.isCorrectSubtype()){
//create instance
}
}
}
What are you asking for is a mapping operation because you have a String as input and you want an Object implementing and interface (ArithmeticOperation) back. If a mpa dose not fit you needs you must "configure" the mapping in a different way, this is my suggestion:
Change the interface to
public interface ArithmeticOperation {
public double performMathOperation(double firstNum, double secondNum);
public double getName();
}
Your add operation will result as the following one:
public class AdditionOperation implements ArithmeticOperation {
public double performMathOperation(double firstNum, double secondNum) {
return firstNum + secondNum;
}
public double getName() {
return "+";
}
}
In you method factory all you need is to find all the classes implementing the ArithmeticOperation interface; something like:
public class ArithmeticOperationFactory {
private List<ArithmeticOperation> availableOperations=null;
//to be called at application startup
public static void findAvailableOperations() {
// a strategy for finding implementations that fills
// availableOperations
}
public static ArithmeticOperation getSpecificOperation(String operation) {
for (ArithmeticOperation arithmeticOperation : availableOperations) {
if (operation.equalsIngoreCase(arithmeticOperation.getName)) {
return arithmeticOperation;
}
}
}
Here are some method you can yous to implement findAvailableOperations:
If you are using Spring you can get the api getBeansOfType and retrieve all the implementations (I'm assuming you are configuring the concrete operations as Spring beans).
If you are not using spring you can scan the classpath in order to find the classes that implement your interface; you can start from this project or this one.
Another solution is to put the implementation class names into a file (.properties, .xml, .json, etc), read the class names and create them via reflection.
You could use a Factory like this
public class ArithmeticOperationFactory {
public static ArithmeticOperation getSpecificOperation(String operation) throws ClassNotFoundException, InstantiationException, IllegalAccessException {
return (ArithmeticOperation) resolveClass(operation).newInstance();
}
private static Class resolveClass(String className) throws ClassNotFoundException {
return Class.forName(className);
}
}
Related
I know my question title is not relevant to what I'm asking, but not getting any better title. But feel free to suggest title. (So it will be helpful for others as well)
Here is the scenario I'm having:
I've enum class as below
public enum CalendarBasis {
FISCAL_YEAR,
CALENDAR
}
This enum is used in multiple objects in project.
I want to know the best practice/design pattern to follow which will be helpful for having functionality based on value of enum. Today there are only two values in CalendarBasis but tomorrow there can be multiple values.
This is what I'm doing currently:
Consider I've Object SpecificElement which has CalendarBasis enum parameter.
public class SpecificElement {
private SpecificValue specificValue; //some object
// few more Objects defined
private CalendarBasis calendarBasis;
//getters & setters
}
Following function do some operations on SpecificElement based on type of calendarBasis.
public Foo doCalculations(SpecificElement specificElement)
{
if(specificElement.getCalendarBasis().equals(CalendarBasis.FISCAL_YEAR)){
//do something based on fiscal & return.
}
if(specificElement.getCalendarBasis().equals(CalendarBasis.CALENDAR)){
//do something based on CALENDAR & return.
}
}
I want to know if I can have something like multiple class Implementations based on Enum values & do operations related to that enum inside implementation class.
There are around 8-10 different functions as doCalculations which has business logic based on enum type.
The code structure I'm following doesn't seems to be good practice.
So it will be helpful if someone can give me light on structuring this kind of scenario.
To give a concrete example of Siddarth Sreeni's answer
You create an interface:
public interface Calculations {
Foo doCalculations(SpecificElement element);
}
Then you have your enum implement the interface:
public enum CalendarBasis implements Calculations {
FISCAL_YEAR {
#Override
public Foo doCalculations(SpecificElement element) {
return new OtherFoo();
}
},
CALENDAR {
#Override
public Foo doCalculations(SpecificElement element) {
return new Foo();
}
}
}
Your main doCalculations method would then look like:
public Foo doCalculations(SpecificElement specificElement) {
return specificElement.getCalendarBasis().doCalculations(specificElement);
}
I think you can use EnumMap. If your strategies are stateless (as appears to be the case in your examples), then you simply initialize a map with all of your strategies and use StrategyType to retrieve the one you want.
enum CalendarBasisStrategyType { FISCAL_YEAR, CALENDAR }
static EnumMap<CalendarBasisStrategyType, CalendarBasisStrategy> lookupStrategy = new EnumMap();
{
lookupStrategy.put(FISCAL_YEAR, new FiscalYearStrategyObject());
lookupStrategy.put(CALENDAR, new CalenderBasisStrategyObject());
}
CalendarBasisStrategy toStrategy(CalendarBasisStrategyType type) {
return lookupStrategy.get(type);
}
If it is not stateless then you can use Factory for Creating Objects.
enum CalendarBasisStrategyType { FISCAL_YEAR, CALENDAR }
static EnumMap<CalendarBasisStrategyType, CalendarBasisFactory> lookupFactory = new EnumMap();
{
...
}
CalendarBasisStrategy toStrategy(CalendarBasisStrategyType type) {
return lookupFactory.get(type).newInstance();
}
I would strongly consider using the Strategy pattern for this. This should help to keep your code clean and maintainable, by separating different calculations into their own classes. You can use a Factory to get the right type of calculation.
public enum CalendarBasis {
FISCAL_YEAR,
CALENDAR
}
public interface Calculation {
double performCalculation();
}
public class FiscalCalculation implements Calculation {
#Override
public double performCalculation() {
//Perform calculation.
}
}
public class CalendarCalculation implements Calculation {
#Override
public double performCalculation() {
//Perform calculation.
}
}
public class CalculationFactory {
public static Calculation getCalculation(CalendarBasis calendarBasis) {
switch (calendarBasis) {
case CALENDAR: return new CalendarCalculation();
case FISCAL_YEAR: return new FiscalCalculation();
default:
//Should not happen.
throw new IllegalArgumentException("Invalid basis: " + calendarBasis);
}
}
}
//Usage
double result = CalculationFactory.getCalculation(specificObject.getCalendarBasis()).performCalculation();
Lets say we need some logic change in multiple methods of multiple classes on basis of a flag, while keeping backwards compatibility.
There are two ways..
1.overload every method in every class. then end up with an if-else ladder in caller code to call correct method.
2.Make a common interface and a Factory. Return objects of either on basis of flag passed to factory. Callers don't need any change. only a little change is needed while object creation. Is it logical to create factory for two types only ?
Based on your experience which will you choose ? How to decide between these two ways ? Any better approach you can suggest ?
Logic change suggests behavior which suggests the Strategy Pattern. This avoids a change to the existing method signature.
But you can still use a factory to centralize the creation of the concrete strategy object which handles the logic.
import java.util.Random;
public class App {
public static void main(String[] args) {
App app = new App();
app.calculateSomething(new Random().nextBoolean());
}
private void calculateSomething(boolean isUsingLegacyLogic) {
CalculationStrategyFactory factory = new CalculationStrategyFactory();
CalculationStrategy strategy = factory.getCalculationStrategy(isUsingLegacyLogic);
Calculator calculator = new Calculator(strategy);
calculator.calculate();
}
class Calculator {
CalculationStrategy calculationStrategy;
Calculator(CalculationStrategy calculationStrategy) {
this.calculationStrategy = calculationStrategy;
}
// ...
public double calculate() {
// original code
// ...
// System.out.println("Calculation steps were done in sequential order.");
// return 0;
return calculationStrategy.calculate(this);
}
}
private interface CalculationStrategy {
double calculate(Calculator c);
}
private class SequentialCalculationHandler implements CalculationStrategy {
public double calculate(Calculator c) {
// ...
System.out.println("Calculation steps were done in sequential order.");
return 0;
}
}
private class ParallelCalculationHandler implements CalculationStrategy {
public double calculate(Calculator c) {
// ...
System.out.println("Calculation steps were done in parralel.");
return 0;
}
}
private class CalculationStrategyFactory {
public CalculationStrategy getCalculationStrategy(boolean isUsingLegacyLogic) {
if (isUsingLegacyLogic || Runtime.getRuntime().availableProcessors() == 1) {
return new SequentialCalculationHandler();
}
return new ParallelCalculationHandler();
}
}
}
I'm working on a java based game with a friend and I've noticed he's taking an approach that concerns me, in terms of maintainability.
For a class representing a playable Character, instead of just creating 1 method which sets an object's property, he's creating separate methods which set the property to a specific value.
Which of these 2 options would be the best to follow going forward?
Option 1
public void runFast() {
this.character.speed = 5.0f
}
public void walk() {
this.character.speed = 2.0f
}
public void stop() {
this.character.speed = 0.0f;
}
Option 2
public void setSpeed(float speedTemp) {
this.character.speed = speedTemp;
}
Why not use an enum to set the speed - then you can still have
void setSpeed(Speed speed) {
this.character.speed = speed.getAmount();
}
with:
enum Speed {
FAST(5.0f), WALK(2.0f), STOP(0.0f);
private final float amount;
private Speed(flaot a) { this.amount = a; }
public float getAmount() {
return amount;
}
}
That way, you can quickly update the values, but still have a predefined amount. Its flexible and easy to maintain. You might want to save the enum instead of the float.
My Solution would be to use Enums instead,
it is cleaner and has more context and easily extensible if you have more to do with your speed maxHeartRate in the future.
public class Character {
private Speed speed;
public Speed getSpeed() {
return speed;
}
public void setSpeed(Speed speed) {
this.speed = speed;
}
};
public enum Speed {
STOP(0),
RUN(5.5),
WALK(2.5);
double value;
Speed(double value) {
this.value = value;
}
public double getValue() {
return value;
}
};
IMHO the best option would be to declare constants/enums, and use the option 2.
Example (constants) :
public static final float STOP = 0.0f;
public static final float WALK = 2.0f;
public static final float FAST = 5.0f;
setSpeed(STOP|WALK|FAST);
Example (enums) :
public enum Speed
{
FAST(5.5f),
STOP(0),
WALK(2.5f);
float value;
Speed(float pValue)
{
this.value = pValue;
}
public float getValue()
{
return this.value;
}
}
setSpeed(Speed.FAST);
It depends. For example
Are speeds limited to a few predefined values? In that case using an enum would be a good solution.
Is walking / running / stopping going have side effects other than just setting the speed? As a contrived example, starting to run might cause the character to drop an item it's holding, or stopping might cause the character to skid a little. In this case having separate methods might make sense.
Or maybe there are only a few predefined states, but depending on the environment running speed might be different.
What it comes down to is: Which way of conceptually modeling the properties of your character works best for your game logic / physics? Work this out and then base the interface of your classes on that. Don't get too hung up on the exact API early on, this sort of stuff is pretty easy to refactor.
getter and setters are useful when you want that your code is readble and for avoiding that public class fields can be used in the wrong way from another classes.
This example show how is important.
CLASS A:
public class ClassA{
// in the body class
private String fieldClass1;
//classic setter
public void setfieldClass1(String f1)
{
fieldClass1 = f1;
}
}
CLASS B:
public class ClassB{
// in the bodyclass
public String fieldClass2;
//classic setter
public void setfieldClass2(String f2)
{
setfieldClass2 = f2;
}
CLASS C:
public class ClassC{
//in the body of the class this method use class a and class b
public void calc()
{
ClassA aObject = new ClassA();
ClassB bObject = new ClassB();
ClassA.fieldClass1 = 5 + 5; // illegal expression for the compiler and costrain the developer to use setters
ClassB.fieldClass2 = 8 + 8; // legal expression
}
}
This mean that you must define a "modifiers logic" (protected, private, public) before make setters and getters. Define before the modifiers and after define the setters and getters.
I am trying to better my understanding Java interfaces and have the following problem with some very basic, code.
The following creates two classes which implement the same interface. I then create two ArrayLists to hold objects of these two classes. I then want to create a single enhanced-for loop which goes through each list and performs the method originally defined in the interface.
I thought that i could use a loop which instead of taking in a specific class type as its parameter could use an Interface type instead, This would then allow me to use any class which implements that interface, but it seems i have made mistake.
How would i go about creating a for loop which allowed only classes which implement an interface to be operated on?
interface Valueing{
double getValue();
}
class Coin implements Valueing
{
private double coinVal = 0.0;
Coin(double initVal){
coinVal = initVal;
}
public double getValue(){
return this.coinVal;
}
}
class Note implements Valueing
{
private int noteVal = 0;
Note(int initVal){
noteVal = initVal;
}
public double getValue(){
return (double)noteVal;
}
}
public class IFaceBasics{
public static void main(String[] args){
ArrayList<Coin> myChange = new ArrayList<Coin>();
myChange.add(new Coin(0.01));
double totalChange = sumValues(myChange);
ArrayList<Note> myNotes = new ArrayList<Note>();
myNotes.add(new Note(5));
double totalNotes = sumValues(myNotes);
}
public double sumValues(ArrayList<Valueing> a){
double totalSum = 0;
for(Valueing avg : a)
{
totalSum += avg.getAverage();
}
return totalSum;
}
}
Thanks for any feedback.
You've almost got it right, you'd just need to change
public double sumValues(ArrayList<Valueing> a){
to
public double sumValues(ArrayList<? extends Valueing> a){
<? extends Valueing> means "Valueing or any of its sub-types", so this would let the method accept an ArrayList<Coin> or ArrayList<Note> as well as ArrayList<Valueing>.
This question already has answers here:
When should I use the Visitor Design Pattern? [closed]
(20 answers)
Closed 5 years ago.
I'm really confused about the visitor pattern and its uses. I can't really seem to visualize the benefits of using this pattern or its purpose. If someone could explain with examples if possible that would be great.
So you've probably read a bajillion different explanations of the visitor pattern, and you're probably still saying "but when would you use it!"
Traditionally, visitors are used to implement type-testing without sacrificing type-safety, so long as your types are well-defined up front and known in advance. Let's say we have a few classes as follows:
abstract class Fruit { }
class Orange : Fruit { }
class Apple : Fruit { }
class Banana : Fruit { }
And let's say we create a Fruit[]:
var fruits = new Fruit[]
{ new Orange(), new Apple(), new Banana(),
new Banana(), new Banana(), new Orange() };
I want to partition the list in to three lists, each containing oranges, apples, or bananas. How would you do it? Well, the easy solution would be a type-test:
List<Orange> oranges = new List<Orange>();
List<Apple> apples = new List<Apple>();
List<Banana> bananas = new List<Banana>();
foreach (Fruit fruit in fruits)
{
if (fruit is Orange)
oranges.Add((Orange)fruit);
else if (fruit is Apple)
apples.Add((Apple)fruit);
else if (fruit is Banana)
bananas.Add((Banana)fruit);
}
It works, but there are lots of problems with this code:
For a start, its ugly.
Its not type-safe, we won't catch type errors until runtime.
Its not maintainable. If we add a new derived instance of Fruit, we need to do a global search for every place which performs a fruit type-test, otherwise we might miss types.
Visitor pattern solves the problem elegantly. Start by modifying our base Fruit class:
interface IFruitVisitor
{
void Visit(Orange fruit);
void Visit(Apple fruit);
void Visit(Banana fruit);
}
abstract class Fruit { public abstract void Accept(IFruitVisitor visitor); }
class Orange : Fruit { public override void Accept(IFruitVisitor visitor) { visitor.Visit(this); } }
class Apple : Fruit { public override void Accept(IFruitVisitor visitor) { visitor.Visit(this); } }
class Banana : Fruit { public override void Accept(IFruitVisitor visitor) { visitor.Visit(this); } }
It looks like we're copy pasting code, but note the derived classes are all calling different overloads (the Apple calls Visit(Apple), the Banana calls Visit(Banana), and so on).
Implement the visitor:
class FruitPartitioner : IFruitVisitor
{
public List<Orange> Oranges { get; private set; }
public List<Apple> Apples { get; private set; }
public List<Banana> Bananas { get; private set; }
public FruitPartitioner()
{
Oranges = new List<Orange>();
Apples = new List<Apple>();
Bananas = new List<Banana>();
}
public void Visit(Orange fruit) { Oranges.Add(fruit); }
public void Visit(Apple fruit) { Apples.Add(fruit); }
public void Visit(Banana fruit) { Bananas.Add(fruit); }
}
Now you can partition your fruits without a type-test:
FruitPartitioner partitioner = new FruitPartitioner();
foreach (Fruit fruit in fruits)
{
fruit.Accept(partitioner);
}
Console.WriteLine("Oranges.Count: {0}", partitioner.Oranges.Count);
Console.WriteLine("Apples.Count: {0}", partitioner.Apples.Count);
Console.WriteLine("Bananas.Count: {0}", partitioner.Bananas.Count);
This has the advantages of:
Being relatively clean, easy to read code.
Type-safety, type errors are caught at compile time.
Maintainability. If I add or remove a concrete Fruit class, I could modify my IFruitVisitor interface to handle the type accordingly, and the compiler will immediately find all places where we implement the interface so we can make the appropriate modifications.
With that said, visitors are usually overkill, and they have a tendency to grossly complicate APIs, and it can be very cumbersome to define a new visitor for every new kind of behavior.
Usually, simpler patterns like inheritance should be used in place of visitors. For example, in principle I could write a class like:
class FruitPricer : IFruitVisitor
{
public double Price { get; private set; }
public void Visit(Orange fruit) { Price = 0.69; }
public void Visit(Apple fruit) { Price = 0.89; }
public void Visit(Banana fruit) { Price = 1.11; }
}
It works, but what's the advantage over this trivial modification:
abstract class Fruit
{
public abstract void Accept(IFruitVisitor visitor);
public abstract double Price { get; }
}
So, you should use visitors when the following conditions hold:
You have a well-defined, known set of classes which will be visited.
Operations on said classes are not well-defined or known in advance. For example, if someone is consuming your API and you want to give consumers a way to add new ad-hoc functionality to objects. They're also a convenient way to extend sealed classes with ad-hoc functionaity.
You perform operations of a class of objects and want to avoid run-time type testing. This is usually the case when you traverse a hierarchy of disparate objects having different properties.
Don't use visitors when:
You support operations on a class of objects whose derived types are not known in advance.
Operations on objects are well-defined in advance, particularly if they can be inherited from a base class or defined in an interface.
Its easier for clients to add new functionality to classes using inheritance.
You are traversing a hierarchy of objects which have the same properties or interface.
You want a relatively simple API.
Once upon a time...
class MusicLibrary {
private Set<Music> collection ...
public Set<Music> getPopMusic() { ... }
public Set<Music> getRockMusic() { ... }
public Set<Music> getElectronicaMusic() { ... }
}
Then you realize you'd like to be able to filter the library's collection by other genres. You could keep adding new getter methods. Or you could use Visitors.
interface Visitor<T> {
visit(Set<T> items);
}
interface MusicVisitor extends Visitor<Music>;
class MusicLibrary {
private Set<Music> collection ...
public void accept(MusicVisitor visitor) {
visitor.visit( this.collection );
}
}
class RockMusicVisitor implements MusicVisitor {
private final Set<Music> picks = ...
public visit(Set<Music> items) { ... }
public Set<Music> getRockMusic() { return this.picks; }
}
class AmbientMusicVisitor implements MusicVisitor {
private final Set<Music> picks = ...
public visit(Set<Music> items) { ... }
public Set<Music> getAmbientMusic() { return this.picks; }
}
You separate the data from the algorithm. You offload the algorithm to visitor implementations. You add functionality by creating more visitors, instead of constantly modifying (and bloating) the class that holds the data.
It provides another layer of abstraction. Reduces complexity of an object and makes it more modular. Sorta like using an interface(implementation being completely independent and no one cares how it is done just that it gets done.)
Now I have never used it but it would be useful for: Implementing a particular function that needs to be done in different subclasses, since each of the sub classes needs to implement it in different ways another class would implement all the functions. Kinda like a module but only for a collection of classes. Wikipedia has a pretty good explanation: http://en.wikipedia.org/wiki/Visitor_pattern
And their example helps explain what I am trying to say.
Hope that helps clear it up a bit.
EDIT**Sorry I linked to wikipedia for your answer but they really do have a decent example :) Not trying to be that guy that says go find it yourself.
Example of visitor pattern. Book, Fruit & Vegetable are basic elements of type "Visitable"
and there are two "Visitors" , BillingVisitor & OfferVisitor each of the visitor has its own purpose .Algo to calculate the bill and algo to calculate the offers on these elements is encapsulated in the respective visitor and the Visitables ( Elements) remain the same.
import java.util.ArrayList;
import java.util.List;
public class VisitorPattern {
public static void main(String[] args) {
List<Visitable> visitableElements = new ArrayList<Visitable>();
visitableElements.add(new Book("I123",10,2.0));
visitableElements.add(new Fruit(5,7.0));
visitableElements.add(new Vegetable(25,8.0));
BillingVisitor billingVisitor = new BillingVisitor();
for(Visitable visitableElement : visitableElements){
visitableElement.accept(billingVisitor);
}
OfferVisitor offerVisitor = new OfferVisitor();
for(Visitable visitableElement : visitableElements){
visitableElement.accept(offerVisitor);
}
System.out.println("Total bill " + billingVisitor.totalPrice);
System.out.println("Offer " + offerVisitor.offer);
}
interface Visitor {
void visit(Book book);
void visit(Vegetable vegetable);
void visit(Fruit fruit);
}
//Element
interface Visitable{
public void accept(Visitor visitor);
}
static class OfferVisitor implements Visitor{
StringBuilder offer = new StringBuilder();
#Override
public void visit(Book book) {
offer.append("Book " + book.isbn + " discount 10 %" + " \n");
}
#Override
public void visit(Vegetable vegetable) {
offer.append("Vegetable No discount \n");
}
#Override
public void visit(Fruit fruit) {
offer.append("Fruits No discount \n");
}
}
static class BillingVisitor implements Visitor{
double totalPrice = 0.0;
#Override
public void visit(Book book) {
totalPrice += (book.quantity * book.price);
}
#Override
public void visit(Vegetable vegetable) {
totalPrice += (vegetable.weight * vegetable.price);
}
#Override
public void visit(Fruit fruit) {
totalPrice += (fruit.quantity * fruit.price);
}
}
static class Book implements Visitable{
private String isbn;
private double quantity;
private double price;
public Book(String isbn, double quantity, double price) {
this.isbn = isbn;
this.quantity = quantity;
this.price = price;
}
#Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
}
static class Fruit implements Visitable{
private double quantity;
private double price;
public Fruit(double quantity, double price) {
this.quantity = quantity;
this.price = price;
}
#Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
}
static class Vegetable implements Visitable{
private double weight;
private double price;
public Vegetable(double weight, double price) {
this.weight = weight;
this.price = price;
}
#Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
}
}
I think the main purpose of visitor pattern is it has high extensibility. The intuition is you've bought a robot. The robot already has fully implemented elementary functionalities as go ahead, turn left, turn right, go back, pick something, speak a phase, …
One day, you want your robot can go to post office for you. With all of these elementary functionalities, it can do, but you need to bring you robot to the shop and "update" your robot. The shop seller do not need to modify the robot, but simply put a new update chip to your robot and it can do what you want.
An other day, you want your robot to go to supermarket. Same process, you has to bring your robot to the shop and update this "advanced" functionality. No need to modify the robot itself.
and so on …
So the idea of Visitor pattern is, given all implemented elementary functionalities, you can use visitor pattern to add an infinite number of sophisticated functionalities. In the example, the robot is your worker classes, and the "update chip" are visitors. Each time need a new "update" of functionality, you don't modify your worker class, but you add a visitor.
It is to separate the data manipulation from the actual data. As a bonus you can reuse the same visitor class for the whole hierarchy of your classes, which again saves you from carrying around the data manipulation algorithms that are irrelevant to your actual objects.