用多态和组合替换多个条件
這是一種眾所周知的重構(gòu)模式,可以將條件條件替換為多態(tài)性。 如果您不熟悉該模式,可以在此處查看 。 但是,一旦該類中有多個條件檢查所基于的字段,該基本解決方案便會開始崩潰。 我們將研究一些有關(guān)如何使用這些可能性的想法。
有很多方法可以解決,因此我們將從最簡單到最困難的工作,始終使用簡單的示例來盡可能減少混亂。 那么,最簡??單的情況是什么? 看一看:
public class ClassWithConditionals {private boolean conditional1;private EnumeratedType conditional2;public ClassWithConditionals(boolean cond1, EnumeratedType cond2){conditional1 = cond1;conditional2 = cond2;}public void method1(){if(conditional1){//do something}else{//do something else}}public void method2(){switch(conditional2){case CASE1://do somethingbreak;case CASE2://do something elsebreak;case CASE3://do something entirely differentbreak;}} }enum EnumeratedType {CASE1,CASE2,CASE3 }因此,在此示例中,我們有ClassWithConditionals在其方法中使用的兩個不同字段。 在一個合適的示例中,您將假設(shè)不僅使用給定的兩個方法,還可以使用更多的方法,但是對于該示例,我們僅需要兩個方法。 如果每個條件只使用一種方法,那么您就不必擔(dān)心,因為維護成本仍然很低。 但是,只要執(zhí)行這種條件檢查的方法數(shù)量增加,就應(yīng)該考慮進行這種重構(gòu)。
通常,如果您要遵循用多態(tài)替換條件,您將最終得到六個類來解決此問題: boolean和enum每個組合都有一個。 取而代之的是,我們將使用合成。
那么,第一步是什么? 首先,我們可能應(yīng)該使用enum類型。 enum可以有自己的方法,可以以允許其根據(jù)特定enum做不同事情的方式定義這些方法。 因此,讓我們將enum eratedType更改如下:
enum EnumeratedType {CASE1(){public void doSomething(){//do something}},CASE2(){public void doSomething(){//do something else}},CASE3(){public void doSomething(){//do something entirely different}};public abstract void doSomething(); }現(xiàn)在, method2僅需要將自身委托給conditional2.doSomething() 。
現(xiàn)在讓我們修復(fù)boolean 。 我們創(chuàng)建一個接口,該接口對所有非封裝類(為了測試起見,可能是包)都私有,稱為Conditional1 。 然后我們用True和False對其進行子類化。 這是代碼:
interface Conditional1 {static Conditional1 TRUE = new True();static Conditional1 FALSE = new False();void doSomething(); }class True implements Conditional1 {public void doSomething(){//do something} }class False implements Conditional1 {public void doSomething(){//do something else} }我決定在接口上創(chuàng)建TRUE和FALSE實例的原因很簡單:它們都是無狀態(tài)類,這意味著每個實例都具有多個實例是沒有意義的。 它還允許我們像enum一樣調(diào)用它們。
同樣,現(xiàn)在主要類僅需要委托。 這是固定類現(xiàn)在的樣子
public class ClassWithConditionals {public static ClassWithConditionals with(boolean cond1, EnumeratedType cond2){Conditional1 conditional1;if(cond1)conditional1 = Conditional1.TRUE;elseconditional1 = Conditional1.FALSE;return new ClassWithConditionals(conditional1, cond2);}private Conditional1 conditional1;private EnumeratedType conditional2;ClassWithConditionals(Conditional1 cond1, EnumeratedType cond2){this.conditional1 = cond1;this.conditional2 = cond2;}public void method1(){conditional1.doSomething();}public void method2(){conditional2.doSomething();} }這里有些奇怪。 我們已經(jīng)用另一個替換了一個條件。 我們的構(gòu)造函數(shù)足以接受一個Conditional1 ,但是我們有一個靜態(tài)工廠方法,該方法仍然采用boolean并對此進行條件檢查。
考慮到從技術(shù)上講,除非有多種方法進行檢查,否則我們不會重構(gòu)此代碼,因此,我們進行了許多檢查并將其歸為一類。 同樣,在工廠中通常認為有條件的還可以,將所有檢查強制到一個位置,并允許多態(tài)性從那里接管。 您不必使用靜態(tài)工廠方法作為工廠,但是它是最快速,最簡單的實時設(shè)置方法。 允許調(diào)用新ClassWithConditionals對象的創(chuàng)建代碼的代碼仍然可以按過去的方式傳遞boolean的另一個好處是,它允許我們封裝和隱藏基于條件的類的實現(xiàn)細節(jié)。 新ClassWithConditionals創(chuàng)建者無需擔(dān)心創(chuàng)建Conditional1對象,甚至無需知道它的存在。
我們?nèi)匀幌M麡?gòu)造函數(shù)接受Conditional1對象,這有兩個原因:1)它將條件邏??輯保存在工廠中,而不是構(gòu)造函數(shù)中,后者是首選,并且2)它允許我們傳遞Conditional1對象的測試雙精度。
實際上,由于第2點,我們應(yīng)該經(jīng)常考慮將其enum轉(zhuǎn)換為更類似于Conditional1的靜態(tài)實例。 這將允許您更多地使用測試雙打。 它還將有助于繼承或通過組合進行擴展,這將在稍后進行討論。
可以想到很多小變化。 首先,條件boolean不需要boolean或enum 。 可以有一組基于數(shù)字或其他條件的條件表達式。 通常,在這些情況下,我們用一個小的輔助方法來代替支票以使其更清晰,即if(numberOfPeople <= 3)...變成if(isACrowd(numberOfPeople))... 我們可以更進一步,并創(chuàng)建通過工廠創(chuàng)建的GroupsOfPeople層次結(jié)構(gòu)。 如果工廠的值為1,則返回SinglePerson ; 給定2,則返回Company對象; 給定3或更多,它將返回一個Crowd對象。 這些對象中的每個對象都有其自己的方法,這樣可以幫助減少原始類中的代碼量。
另一個變化是當(dāng)不同的條件字段集分層在一起時( if(condition1 && condition2)等)。 為了解決這個問題,您可以走繼承路線并創(chuàng)建爆炸的類以覆蓋所有組合。 另一個選擇是用一個小的層次結(jié)構(gòu)替換一個條件對象,該層次結(jié)構(gòu)接受委托方法中的其他條件對象,在該方法中,它仍然具有一些條件代碼,但是可讀性更強。 例如,您可以將使用兩個布爾值的類轉(zhuǎn)換為如下形式:
public class ClassWithConditionals {public static ClassWithConditionals with(boolean condition1, boolean condition2){Conditional1 cond1;if(condition1)cond1 = Conditional1.TRUE;elsecond1 = Conditional1.FALSE;return new ClassWithConditionals(cond1, condition2);}private Conditional1 condition1;private boolean condition2;ClassWithConditionals(Conditional1 condition1, boolean condition2){this.condition1 = condition1;this.condition2 = condition2;}public void method(){condition1.method(condition2);} }interface Conditional1 {static Conditional1 TRUE = new True();static Conditional1 FALSE = new False();void method(boolean condition2); }class True implements Conditional1 {public void method(boolean condition2){if(condition2){//do something}else{//do something else}} }class False implements Conditional1 {public void method(boolean condition2){if(!condition2){//do something really different}//and do this} }Condition1的method接受一個布爾值,然后使用它進行更多的條件處理。
另外,如果所有邏輯都允許,則可以創(chuàng)建一組類來替換其中一個條件,然后讓其創(chuàng)建代碼接受其他條件以決定其創(chuàng)建的一部分。 例如:
public class ClassWithConditionals {public static ClassWithConditionals from(boolean condition1, boolean condition2){return new ClassWithConditionals(Conditional1.from(condition1, condition2));}private Conditional1 conditionOne;ClassWithConditionals(Conditional1 conditionOne){this.conditionOne = conditionOne;}public int method(){return conditionOne.method() * -6;} }interface Conditional1 {static Conditional1 from(boolean condition1, boolean condition2){if(condition1)return True.with(condition2);elsereturn False.with(condition2);}int method(); }class True implements Conditional1 {public static True with(boolean condition2){if(condition2)return new True(5);elsereturn new True(13);}private int secondary;public True(int secondary){this.secondary = secondary;}public int method(){return 2 * secondary;} }class False implements Conditional1 {public static False with(boolean condition2){if(condition2)return new False((x, y) -> x - y, 31);elsereturn new False((x, y) -> x * y, 61);}private final BinaryOperator operation;private final int secondary;public False(BinaryOperator operation, int secondary){this.operation = operation;this.secondary = secondary;}public int method(){return operation.apply(4, secondary);} }對于True ,第二個條件決定method計算中的次要數(shù)字。 在False ,它會執(zhí)行此操作并找出要應(yīng)用于計算的運算符。
我不確定是否會發(fā)生類似的事情,但是如果確實發(fā)生了,您現(xiàn)在知道了一種解決方法。
總的來說,這整套重構(gòu)從本質(zhì)上將代碼從單個類更改為Facade。 它需要大量的新類,并且使您可以使用與以前的單個類幾乎完全相同的方式來使用整個工具包和kaboodle,唯一真正的區(qū)別是調(diào)用靜態(tài)工廠方法而不是構(gòu)造函數(shù)。
這不是特別重要; 我只是想向您指出。
希望您不必擔(dān)心繼承或“通過合成擴展”此類。 但是您可能必須這樣做。
如果您要編寫的擴展僅真正改變了條件對象的功能,則可以簡單地編寫一個新的Factory,為構(gòu)造函數(shù)提供一組新的條件對象。 例如,您可以將此靜態(tài)工廠方法添加到ClassWithConditionals的最新版本中:
public static ClassWithConditionals different(int value) {return new ClassWithConditionals(new SimpleConditional1(value)); }與SimpleConditional1看起來像這樣
class SimpleConditional1 implements Conditional1 {private final int value;public SimpleConditional1(int value){this.value = value;}public int method(){return value;} }除此之外,您還可以提供原始需要的任何條件對象,并覆蓋您需要覆蓋的所有方法。
因此,這就是我用一個更多的OO選項替換多個條件的結(jié)果。 您還有其他方法可以做到嗎? 您是否有一個無法奏效的示例,您希望我對此加以抨擊? 讓我知道,我會看看可以做什么。
謝謝閱讀。
翻譯自: https://www.javacodegeeks.com/2015/01/replacing-multiple-conditionals-with-polymorphism-and-composition.html
總結(jié)
以上是生活随笔為你收集整理的用多态和组合替换多个条件的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 苹果电脑mac游戏推荐(mac电脑的游戏
- 下一篇: 如何轻松配置上网行为管理功能路由器如何设