1

I have the following class (in JEE, can be made similarly in Spring):

@Singleton
public class MyUnknownPatternClass {
    @Inject @Any Instance<SomeInterface> instances;

    public SomeInterface getMatchingInstance(Object someDiscriminator) {
        for(SomeInterface instance : instances) {
            if(instance.supports(someDiscriminator)) {
                return instance;
            }
        }
        throw new IllegalArgumentException("Could not find a matching instace for " + someDiscriminator.toString());
     }
}

Using dependency injection's discovery to locate all instances of the matching interface, this allows me to totally decouple strategies and the code using it.

For example, with a travelling salesman application, and I'm having different TransportProviders which implement a travel(Location l) method, my business logic can then focus on following regular flow:

Salesman m =...;
Location l =  m.getStartLocation();
TransportProvider t = myUnknownPatternClass.getMatchingInstance(m.getTravelMethod());
for(Location d : m.getDestinationsToVisit())
    l = t.travel(d);
    m.doBusinessHere(l);
}

Thus decoupling whether the salesman travels by foot, boat, car, or any other method.

My understanding is that a factory actually instantiates objects. A servicelocator is more generic, and allows for runtime registration, and the above code seems to do neither. It is not a whiteboard pattern, as it only returns a single instance.

However, it's a very useful pattern, and it would be nice to talk about it properly.

What, then, is it?
And what would then be a proper name for the class (i.e. SomeInterfaceLocator, or SomeInterfaceFactory)?

Edit: I found this https://en.wikipedia.org/wiki/Command_pattern#Java_8
Is it a command factory pattern?

Koos Gadellaa
  • 1,220
  • 7
  • 17
  • Looks like a factory to me -- supplies an object of the expected type given a set of parameters. The fact that the instances it returns are instantiated via DI doesn't change its function, just its underlying implementation. – dbugger Jun 29 '16 at 19:21
  • Isn't a factory's 'description' implying that the returned value is yours (i.e. not shared)? Since usually factories return unique objects which can be modified, adjusted, deleted, etc. This doesn't alow that (although it's hard anyway since the interface probably doesn't allow it). If you were describing this to others, would you call it a factory-but-different, and if so, what? – Koos Gadellaa Jun 30 '16 at 11:02
  • It returns a instance -- there's no way for the consumer to know the instance is shared -- it can be modified through any of its properties or methods that allow such behavior. The instances injected into the constructor could be new instances, this object has no way of knowing or enforcing that -- it only knows it has a list of objects. Call it whatever makes sense to you, but from the outside it looks and smells and acts like a factory. – dbugger Jun 30 '16 at 11:54
  • See also https://stackoverflow.com/questions/5698026/is-the-service-locator-pattern-any-different-from-the-abstract-factory-pattern – Michael Freidgeim Feb 03 '23 at 22:55

2 Answers2

0

This implementation is not the Factory because it doesn't create new instances.

It isn't Service Locator either, because it is not locating services - now this requires a few words of explanation.

Service locator should return distinct interfaces. Your method is returning objects implementing a single common interface. Here is the signature of a Service Locator:

T LocateService<T>() { ... }

This is the dreaded signature which has caused so much troubles to developers worldwide. The problem is that signature of this method doesn't tell what is the kind of objects the consumer may depend on. Let me show it with a longer example:

class ServiceLocator {
    T Locate<T>();
}

class Golum {

    ServiceLocator locator;

    Consumer(ServiceLocator depedency) { ... }

    void beNice() {
        Preciousss myPrecious = this.locator.Locate<Previousss>();
        myPrecious.DoMagic();
    }
}

void main() {
    new Golum(new ServiceLocator()).beNice(); // Fails!
}

This piece of code is the sublimation of all evil that comes with misuse of service locators. Main function is initializing the Golum class, but it has no clue what Golum requires. Golum just asks for a service locator, any service locator, and then gets going. When beNice method is invoked, it turns that particular service locator object that was passed has no knowledge of the Preciousss class at all, and then call to Locate fails.

Bottom line, negative consequences appear when a class doesn't declare its dependencies explicitly. And if you take a look at your case, this is not what happens there. Your class depends on SomeInterface and then asks for the resolver object which also knows of SomeInterface. I don't see negative consequences there.

When talking about naming, I might choose to call that "locator" object something like SomeInterfaceLookup, although SomeInterfaceLocator wouldn't be any worse than that.

Zoran Horvat
  • 10,924
  • 3
  • 31
  • 43
  • So we're in agreement that it's not a service locator, not a factory, but maybe a Lookup class. But the question is really, what is the name of this pattern to describe it properly to others. If describing this to others would it be easier to say it's a 'sort-of-factory', or something else? – Koos Gadellaa Jun 30 '16 at 10:58
0

I think I'll go with (Strategy)Selector as a pattern. It's not 100 official, but that's what it does.
Unless someone finds a better name, it's to show that it's not a servicelocator, it's not a factory, not a command pattern.

Koos Gadellaa
  • 1,220
  • 7
  • 17