Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
63 views
in Technique[技术] by (71.8m points)

java - Can I call this an SPI pattern?

Given a hypothetical TransportConsultancy business that provides cost of travel by various airlines to its customers.

New airlines can register themselves with the consultancy, but must adhere to the contract by defining a method getCostPerUnitDistance which returns an integer.

Here's the TransportConsultancy's business logic:

import org.apache.commons.io.FileUtils;

import java.io.File;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class TransportConsultancy {
    public static enum Location {
        Seattle(5),
        SanFrancisco(10),
        Portland(1),
        Denver(13);

        private int distanceFromHub;

        Location(int distanceFromHub) {
            this.distanceFromHub = distanceFromHub;
        }
    }

    private List<String> readRegistry() {
        try {
            return FileUtils.readLines(new File("src/main/resources/AirlineRegistry"), StandardCharsets.UTF_8);
        } catch(Exception e) {
            throw new RuntimeException("Unable to lookup registry", e);
        }
    }

    public List<String> getAirlineList() {
        return readRegistry().stream().map(s -> s.split(",")[0])
                .collect(Collectors.toList());
    }

    public List<String> getLocationList() {
        return Arrays.asList(Location.values())
                     .stream().map(l -> l.name())
                     .collect(Collectors.toList());
    }

    private Class getAirlineSPIInstance(final String airline) {
        try {
            URLClassLoader loader =
                    new URLClassLoader(new URL[]{new URL(
                            "file:///Users/tester
. /ws/spisample/"
                    )});
            return loader.loadClass(readRegistry().stream().filter(s -> s.startsWith(airline))
                    .findFirst().get() // I know, this isn't production code.
                    .split(",")[1]);
        } catch (ClassNotFoundException | MalformedURLException e) {
            throw new RuntimeException("Unable to load SPI instance for airline " + airline, e);
        }
    }

    private int getCostPerUnitDistanceFromSPIInstance(final Class spiInstance) {
        try {
            for (Method m : spiInstance.getDeclaredMethods()) {
                if (m.getName().equals("getCostPerUnitDistance")) {
                    Object instance = spiInstance.newInstance();
                    return (Integer) m.invoke(instance);
                }
            }
            throw new RuntimeException("Class does not define getCostPerUnitDistance method");
        } catch (InstantiationException | IllegalAccessException | InvocationTargetException e) {
            throw new RuntimeException("Unable to getCostPerUnitDistance", e);
        }
    }

    public int getCost(final String airline, final Location start, final Location end) {
        return getCostPerUnitDistanceFromSPIInstance(getAirlineSPIInstance(airline))
                * (start.distanceFromHub + end.distanceFromHub);
    }
}

Now, this business has an agent who interacts with the customers:

import java.util.Scanner;

public class TransportConsultancyAgent {
    public static void main(final String a[]) {
        TransportConsultancy c = new TransportConsultancy();
        Scanner s = new Scanner(System.in);
        System.out.println("Locations: ");
        c.getLocationList().forEach(System.out::println);
        System.out.print("Enter start location: ");
        String start = s.nextLine();
        System.out.println();
        System.out.print("Enter end location: ");
        String end = s.nextLine();
        System.out.println();
        System.out.println("Airlines: ");
        c.getAirlineList().forEach(System.out::println);
        System.out.print("Enter airline: ");
        String airline = s.nextLine();
        System.out.println("COST IS: ");
        System.out.println(c.getCost(airline, TransportConsultancy.Location.valueOf(start), TransportConsultancy.Location.valueOf(end)));
    }
}

public class MyAirline {
    public int getCostPerUnitDistance() {
        return 10;
    }
}
public class YourAirline {
    public int getCostPerUnitDistance() {
        return 8;
    }
}

Finally

  1. I compile the above two, and put their bytecodes into the class path,
  2. Make the following entries in the registry file:
    MyAirline,MyAirline
    YourAirline,YourAirline
    
  3. And then, run java TransportConsultancyAgent

This is doing what I wanted it to do. Can I now claim I have implemented SPI pattern?

question from:https://stackoverflow.com/questions/66059427/can-i-call-this-an-spi-pattern

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)
Waitting for answers

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...