Design Pattern: Visitor Pattern in Java

Visitor pattern is used to move the operation/calculation part from a group of classes to a completely separate(Visitor) class.

Check complete details and explanations about Visitor pattern in the article: Visitor Design Pattern

This article demonstrates Visitor pattern implementations in Java. Check the following examples.

Example #1: Hosting Cost Calculator

Let’s consider an example of a hosting service, and calculate the total cost of the hosting service used using the visitor pattern.

Service Interface

// Service.java

package com.bigboxcode.designpattern.visitor.hosting;

public interface Service {

    double accept(HostingCalculatorVisitor hostingCalculatorVisitor);
}

Compute Service Class

// ComputeService.java

package com.bigboxcode.designpattern.visitor.hosting;

public class ComputeService implements Service {

    private final double price = 10.50;
    private int quantity;

    public ComputeService(int quantity) {
        this.quantity = quantity;
    }

    public double getPrice() {
        return price;
    }

    public int getQuantity() {
        return quantity;
    }

    @Override
    public double accept(HostingCalculatorVisitor hostingCalculatorVisitor) {
        return hostingCalculatorVisitor.visit(this);
    }
}

Database Service Class

// DatabaseService.java

package com.bigboxcode.designpattern.visitor.hosting;

public class DatabaseService implements Service {

    private final double price = 100.00;
    private final double backPrice = 30.00;
    private int quantity;
    private boolean backupEnabled = false;

    public DatabaseService(int quantity) {
        this.quantity = quantity;
    }

    public DatabaseService(int quantity, boolean backupEnabled) {
        this.quantity = quantity;
        this.backupEnabled = backupEnabled;
    }

    public double getPrice() {
        return price;
    }

    public int getQuantity() {
        return quantity;
    }

    public double getBackPrice() {
        return backPrice;
    }

    public boolean isBackupEnabled() {
        return backupEnabled;
    }

    @Override
    public double accept(HostingCalculatorVisitor hostingCalculatorVisitor) {
        return hostingCalculatorVisitor.visit(this);
    }
}

File Storage Service Class

// FileStorageService.java

package com.bigboxcode.designpattern.visitor.hosting;

public class FileStorageService implements Service {

    private final double pricePerGB = 1.70;
    private int quantity;

    public FileStorageService(int quantity) {
        this.quantity = quantity;
    }

    public double getPricePerGB() {
        return pricePerGB;
    }

    public int getQuantity() {
        return quantity;
    }

    @Override
    public double accept(HostingCalculatorVisitor hostingCalculatorVisitor) {
        return hostingCalculatorVisitor.visit(this);
    }
}

Serverless Service Class

// ServerlessService.java

package com.bigboxcode.designpattern.visitor.hosting;

public class ServerlessService implements Service {

    private final double hourlyPrice = 0.32;
    private int totalHours;

    public ServerlessService(int totalHours) {
        this.totalHours = totalHours;
    }

    public double getHourlyPrice() {
        return hourlyPrice;
    }

    public int getTotalHours() {
        return totalHours;
    }

    @Override
    public double accept(HostingCalculatorVisitor hostingCalculatorVisitor) {
        return hostingCalculatorVisitor.visit(this);
    }
}

Container Service Class

// ContainerService.java

package com.bigboxcode.designpattern.visitor.hosting;

public class ContainerService implements Service {

    private final double price = 5.60;
    private int quantity;

    public ContainerService(int quantity) {
        this.quantity = quantity;
    }

    public double getPrice() {
        return price;
    }

    public int getQuantity() {
        return quantity;
    }

    @Override
    public double accept(HostingCalculatorVisitor hostingCalculatorVisitor) {
        return hostingCalculatorVisitor.visit(this);
    }
}

Visitor Interface

// HostingCalculatorVisitor.java

package com.bigboxcode.designpattern.visitor.hosting;

public interface HostingCalculatorVisitor {

    double visit(ComputeService computeService);

    double visit(ContainerService containerService);

    double visit(DatabaseService databaseService);

    double visit(FileStorageService fileStorageService);

    double visit(ServerlessService serverlessService);
}

Visitor Interface Implementation

// HostingCalculatorVisitorImpl.java

package com.bigboxcode.designpattern.visitor.hosting;

public class HostingCalculatorVisitorImpl implements HostingCalculatorVisitor {
    @Override
    public double visit(ComputeService computeService) {
        return computeService.getPrice() * computeService.getQuantity();
    }

    @Override
    public double visit(ContainerService containerService) {
        return containerService.getPrice() * containerService.getQuantity();
    }

    @Override
    public double visit(DatabaseService databaseService) {
        double serviceCost = databaseService.getPrice() * databaseService.getQuantity();
        double backupCost = 0;

        if (databaseService.isBackupEnabled()) {
            backupCost = databaseService.getBackPrice() * databaseService.getQuantity();
        }

        return serviceCost + backupCost;
    }

    @Override
    public double visit(FileStorageService fileStorageService) {
        return fileStorageService.getPricePerGB() * fileStorageService.getQuantity();
    }

    @Override
    public double visit(ServerlessService serverlessService) {
        return serverlessService.getHourlyPrice() * serverlessService.getHourlyPrice();
    }
}

Demo

// Demo.java

package com.bigboxcode.designpattern.visitor.hosting;


public class Demo {
    public static void main(String[] args) {
        Service[] usedServices = new Service[] {
                new ComputeService(3),
                new DatabaseService(3, true),
                new FileStorageService(120),
                new ServerlessService(720),
                new ContainerService(2),
        };

        double totalCost = calculateHostingCost(usedServices);

        System.out.println("Total cost of hosting is: " + totalCost);
    }

    private static double calculateHostingCost(Service[] services) {
        HostingCalculatorVisitorImpl hostingCalculatorVisitorImpl = new HostingCalculatorVisitorImpl();

        double totalCost = 0;

        for (Service service: services) {
            totalCost += service.accept(hostingCalculatorVisitorImpl);
        }

        return totalCost;
    }
}

Output

Total cost of hosting is: 636.8024

Source Code

Use the following link to get the source code:

Leave a Comment