这种模式是服务定位器、命令工厂还是其他什么?

Is this pattern a service locator, or a command factory, or something else?

我有以下 class(在 JEE 中,可以在 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());
     }
}

使用依赖注入的发现来定位匹配接口的所有实例,这使我能够完全解耦策略和使用它的代码。

例如,对于旅行推销员应用程序,我有不同的 TransportProvider 实现 travel(Location l) 方法,我的业务逻辑可以专注于以下常规流程:

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

从而将推销员是步行、乘船、乘汽车还是任何其他方式旅行分离开来。

我的理解是,工厂实际上是实例化对象。 servicelocator 更通用,允许运行时注册,而上面的代码似乎两者都不做。它不是白板模式,因为它只是 returns 一个实例。

不过,这是一个非常有用的模式,适当地谈论它会很好。

那么,它是什么?
那么 class 的专有名称是什么? (即 SomeInterfaceLocatorSomeInterfaceFactory)?

编辑: 我找到了这个 https://en.wikipedia.org/wiki/Command_pattern#Java_8
是命令工厂模式吗?

此实现不是工厂,因为它不创建新实例。

它也不是服务定位器,因为它不定位服务 - 现在这需要解释几句。

服务定位器应该return 不同的接口。您的方法是 returning 实现单个公共接口的对象。这是服务定位器的签名:

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

这是一个可怕的签名,给全世界的开发者带来了很多麻烦。问题是这个方法的签名没有告诉消费者可能依赖的对象类型。让我用一个更长的例子来展示它:

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!
}

这段代码是滥用服务定位器带来的所有邪恶的升华。主要功能是初始化 Golum class,但它不知道 Golum 需要什么。 Golum 只需要一个服务定位器,任何服务定位器,然后就可以开始了。当调用 beNice 方法时,它会变成传递的特定服务定位器对象根本不知道 Preciousss class,然后调用 Locate 失败。

最重要的是,当 class 没有明确声明其依赖项时,就会出现负面后果。如果你看一下你的案例,这不是那里发生的事情。您的 class 依赖于 SomeInterface,然后请求也知道 SomeInterface 的解析器对象。我没有看到那里的负面后果。

在谈到命名时,我可能会选择将 "locator" 对象称为 SomeInterfaceLookup,尽管 SomeInterfaceLocator 不会比那更糟。

我想我会使用 (Strategy)Selector 作为模式。这不是官方的 100,但这就是它的作用。
除非有人找到更好的名字,否则只能表明它不是服务定位器,不是工厂,不是命令模式。