lundi 8 août 2022

Visitor pattern for classes from external library

I want to use visitor pattern to extend functionality of classes from external library. The main problem that I can't add any new code to that library. Let's consider simple example.

External elements, which require functionality extension will be represented as tools for home work

public interface Tool {
    String name();
}

public record Saw(String name, String purpose) implements Tool {}

public record Screwdriver(String name, String nozzle) implements Tool {}

public record Wrench(String name, int size) implements Tool {}

And new functionality, which I want to add will be represented as workers

public interface Worker<T extends Tool> {
    Class<T> getToolClass();
    void doWork(T tool);
}

Saw worker

public class SawWorker implements Worker<Saw> {

    @Override
    public Class<Saw> getToolClass() {
        return Saw.class;
    }

    @Override
    public void doWork(Saw tool) {
        System.out.println("Sawing with " + tool);
    }
}

Screwdriver worker

public class ScrewdriverWorker implements Worker<Screwdriver> {

    @Override
    public Class<Screwdriver> getToolClass() {
        return Screwdriver.class;
    }

    @Override
    public void doWork(Screwdriver tool) {
        System.out.println("Tightens screw with " + tool);
    }
}

Wrench worker

public class WrenchWorker implements Worker<Wrench> {

    @Override
    public Class<Wrench> getToolClass() {
        return Wrench.class;
    }

    @Override
    public void doWork(Wrench tool) {
        System.out.println("Tightens bolt with " + tool);
    }
}

And main class to start the show

public class Main {
    public static void main(String[] args) {
        List<Tool> tools = List.of(
                new Saw("hand saw", "for gardener"),
                new Saw("chainsaw", "for forester"),
                new Screwdriver("torque screwdriver", "line"),
                new Screwdriver("powered screwdriver", "cross"),
                new Wrench("open-end wrench", 12),
                new Wrench("combination wrench", 32));

        Map<Class<? extends Tool>, Worker> workers = Stream.of(
                new SawWorker(),
                new ScrewdriverWorker(),
                new WrenchWorker()
        ).collect(Collectors.toMap(Worker::getToolClass, Function.identity()));

        tools.forEach(tool -> workers.get(tool.getClass()).doWork(tool));
    }
}

What do you think about such implementation of the pattern? Is it possible to upgrade this solution with use of java8 lambdas? And will it look easier and clearer?

Aucun commentaire:

Enregistrer un commentaire