具有 "complex" 条件且没有 'switch'/'if' 语句的处理策略

Handling strategies with "complex" conditions without 'switch'/'if' statements

我正在开发一个不久将用于配置的应用程序。情况并不复杂。该应用程序管理有权访问服务的组。根据组有权访问的服务,应用不同的业务规则。

第一个想法(简单而愚蠢)是有一个大的 if/else 或 switch/case 来涵盖所有情况。这是它在伪代码中的样子:

if (serviceA OR serviceB) {
    doActionA();
}
if(serviceA AND serviceC) {
    doActionA();
    doActionB();
}
if(serviceB AND serviceC) {
    doActionA();
    doActionC();
}
if(serviceA AND serviceB AND serviceC) {
    doActionA();
    doActionB();
    doActionC();
}
if(serviceD) {
    doActionD();
}

这不是很方便,因为如果添加新服务,我将需要更新此语句(可能是 hundreds/thousands 行!)。

意识到这一点后,我研究了哪种设计模式可以帮助我解决这个问题。看起来可以帮助我的是策略模式。同样,它不会改变任何东西(或者我不明白),代码看起来像这样:

if (serviceA OR serviceB) {
    setStrategy(new StrategyA);
}
if(serviceA AND serviceC) {
    setStrategy(new StrategyB);
}
if(serviceB AND serviceC) {
    setStrategy(new StrategyC);
}
if(serviceA AND serviceB AND serviceC) {
    setStrategy(new StrategyD);
}
if(serviceD) {
    setStrategy(new StrategyE);
}

strategy.run();

在某种程度上,这更糟,因为我只能有一个策略,并注意到 serviceD 没有与其他人相关的业务规则(它只有一个动作)。再说了,可能是我没看懂这个模式。

你知道我该如何以最优雅的方式处理这种情况吗?我知道将来我会有新的服务,所以我现在不想犯错误。 我希望我不需要为每个组合都写一个策略(3 个服务的 7 个策略,4 个服务的 14 个策略,速度很快!)

提前感谢您的帮助:)

在不让业务规则和所有动物园变得不必要复杂的情况下,我只定义谓词-策略对。

对于谓词,您需要某种 Context 来检查 context.isServiceA()

对于该策略,您可能还需要某种 ExecutionContext(如果您的策略是独立的,则可能不需要)。

所以 Predicate<Context> 将检查策略是否适用,而 Consumer<ExecutionContext> 将是策略。那么你只需要某种 Predicate<Context>/Consumer<ExecutionContext> 对的集合。如果您不想写任何额外的 类,只需使用 LinkedHashMap。类似于:

Map<Predicate<Context>, Consumer<ExecutionContext> rules = new LinkedHashMap<>();

rules.put(ctx -> ctx.isServiceA() || ctx.isServiceB(), new StrategyA());
rules.put(ctx -> ctx.isServiceA() && ctx.isServiceC(), new StrategyB());

以此类推

对于语法糖,您可以将 ctx -> ctx.isServiceA() 之类的东西定义为常量,然后

rules.put(SERVICE_A.or(SERVICE_B), new StrategyA());

在评估期间,您只需遍历条目并执行第一个合适的策略。类似于:

rules
.entrySet()
.filter(entry -> entry.getKey().test(context))
.findFirst()
.map(Entry::getValue)
.ifPresent(strategy -> strategy.accept(executionContext));

另一个想法是让策略自己决定它们是否适用。所以一个策略将有一个 test 方法(或谓词)和 apply 方法。然后,您只需寻找适用的策略即可执行。我经常将此与 Spring bean 自动发现结合使用。一些中央bean收集一些策略接口的所有实现,然后选择适用于某些conditions/context.

的一个