2016-11-07 79 views
1

我正在研究即將用於供應的應用程序。情況並不複雜。該應用程序管理有權訪問服務的組。根據組可以訪問的服務,應用不同的業務規則。在沒有'switch'/'if'語句的情況下處理具有「複雜」條件的策略

第一個想法(簡單和愚蠢)將是一個大的if/else或開關/案例,將涵蓋所有的情況。這裏是如何可能看起來像僞代碼:

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(); 
} 

這是不是很方便,因爲如果添加新的服務,我需要更新此聲明(這可能是數百/千線的長!)。

在意識到這一點之後,我做了一些關於哪種設計模式可以幫助我解決這個問題的研究。看起來像這樣的人可能會幫助我成爲戰略模式。再次,它不會改變任何東西(或者我不明白),代碼是這樣的:

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如何沒有與他人相關的商業規則(它只是有一個自己的行動)。然後,也許我不明白這種模式。

你有什麼想法我怎麼能以最優雅的方式處理這種情況?我知道將來我會有新的服務,所以我現在不想犯錯。 我希望我不需要寫策略每個組合(7個策略3個服務,14個策略4個服務,它跑得快!)

感謝您通過您的幫助:)

回答

1

不用使事情變得不必要的複雜與商業規則和所有動物園,我只是定義謂詞策略對。

對於謂詞你需要某種形式的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收集一些策略接口的所有實現,然後選擇適用於某些條件/上下文的那個。

+0

感謝您的回答!不幸的是,我不是用java而是用php工作。不過,我想我明白你的意思。基本上你建議在某種配置文件中編寫規則,在我的「主」中循環我的規則,然後執行那些正常的規則,對吧?有了這個解決方案,無論我需要一個適用於每種情況的規則(針對每個組合的規則),這都不方便,或者我可能會多次調用相同的策略(在我的示例中,如果我有serviceA和serviceB,它會執行actionA兩次)。 – Ryuu

+0

我建議,一個策略在適用時也會提供一個謂詞。你如何編碼這完全取決於你。不,您不一定需要針對每種情況或重複調用的規則。就像在你發佈的代碼中,你有一些命令,一些規則的優先級。一旦你找到了一個最合適的規則,你只需調用策略並返回。你不需要進一步迭代。 – lexicore

+0

我明白了。但是,如果我不重複,我仍然必須使用多種策略。如果小組有服務A和D,我有兩種不同的行動(所以2種策略)。令我困擾的是,我將擁有完全相同的操作但具有不同參數的策略,並且我可能無法爲該策略和其他策略創建足夠通用的接口。我的另一個(也是最後一個)問題是我有多個涉及同一外部應用程序的操作。如果我在X戰略中削減他們,我將不得不調用X時間相同的WS來獲取戰略信息。你知道我可以預防嗎? – Ryuu

相關問題