2010-11-12 51 views
2

我在它與一些國家的枚舉:重構if語句使用適當的模式

enum State 
{ 
    A, 
    B, 
    C, 
    D 
} 

,並具有相應狀態的對象:

class MyObject 
{ 
    State state; 
} 

我需要寫一個算法,需要兩個MyObject實例並根據這些實例的特定狀態執行一些操作:

void doWork(MyObject o1, MyObject o2) 
{ 
    if (o1.state == A && o2.state == A) 
    { 
      // do something 
    } 
    else if (o1.state == A && o2.state == B) 
    {} 
    // etc for all combinations... 

} 

顯然這種方法有很多問題,我想將其改爲理想地擺脫if/else語句。

這樣的要求是否有任何模式?

感謝

+3

@ org.life.java:廢話 - 使用==是枚舉完全安全的。 – 2010-11-12 19:40:01

+1

@邁克爾博格瓦特我道歉,刪除評論也是同樣的情形''==更優選,從這個http://stackoverflow.com/questions/1750435/comparing-java-enum-members-or-equals – 2010-11-12 19:53:12

回答

3

可以做,雖然我不知道它會什麼要好得多,是某種2個state值的所有可能組合的矩陣;您可以使用o1.stateo2.state作爲該矩陣的索引。

你可以不同的東西存儲在該矩陣:

  • 獨特的價值,你可以作爲一個switch塊將取代你的if .. else if .. else塊判別值使用 - 沒有太大的改善,真的。

或者你的矩陣可以包含...

如果你真的想擺脫if陳述,即第二個選項可能是更好的一個;但是,請注意,您的代碼將不再在一個位置靠近在一起,例如if/switch塊,但分佈在幾個不同的命令對象/類中。

// forgive my syntax errors etc., my Java has definitely gone a little rusty! 

interface WorkCommand { 
    public abstract void run(MyObject o1, MyObject o2); 
} 

... 

Map<Pair<State,State>, WorkCommand> commands; 
//^pseudo-code type for your command look-up map; type Pair<X,Y> doesn't exist, 
// so replace this with something sensible! 

void doWork(MyObject o1, MyObject o2) 
{ 
    WorkCommand worker = commands.get(new Pair<State,State>(o1, o2)); 
    worker.run(o1, o2); 
} 
1

我倒是這樣做很可能,它至少更具可讀性,你可以構建這個

void doWork(MyObject o1, MyObject o2) { 
    switch (o1.state) { 
     case A: { 
      switch (o2.state) { 
       case A: { 

        break; 
       } 
       case B: { 

        break; 
       } 

      } 
      break; 
     } 
    } 
} 
2

一個方法,就是你可以在你的枚舉一個抽象的方法,它的每個元素將實施:

enum State 
{ 
    A{ 
     public void void doSomeWork(State state){ 
     switch(state){ 
      case A: 
      case B: 
      ... 
     } 
     } 
    }, 
    B, 
    C, 
    D 

    abstract void doSomeWork(State state); 
} 

然後你的方法能像

void doWork(MyObject o1, MyObject o2){ 
    o1.state.doSomeWork(o2.state); 
} 
0

僅使用兩個狀態組合,嵌套開關可能是最快的實現和理解:

switch (o1.state) { 
case X: switch(o2.state) { } 
//..etc 
} 

如果情況順序是不相關的某些組合,您可以交換o1o2這些的情況下,然後將其放入switch(並避免重複的代碼)。此外,對於具有相同行爲的所有案例組合,您可以利用「跌倒」行爲。

最後,實現這種方式可能使什麼實際發生的事情與這些組合一點更爲明顯,例如,你可能能夠實現一個更聰明的方法。

2

是的,它被稱爲... state pattern。重要的是隻有一個狀態可以定義行爲,即你可能需要將你的object1.state和object2.state組合成一個元狀態。用statecontext註冊這個元狀態,這樣當Myobject.state更改元狀態時就會更新。

interface MyObjectStates { 
    void doWork(MyObject o1, MyObject o2); 
} 

class MyObjectStatesAA implements MyObjectStates { 
    void doWork(MyObject o1, MyObject o2) { 
    // do dowork for both states A 
    } 

class MyObjectStatesBB implements MyObjectStates { 
    void doWork(MyObject o1, MyObject o2) { 
    // do dowork for both states B 
    } 

// etc 

然後,您需要在statecontext中保存一個MyObjectStates對象,並在更改MyObject.state時更新它。你甚至可以全部移除狀態枚舉。如果這種方法聽起來很有趣,你給我一個筆記,我會詳細說明你是否喜歡。

狀態模式有,你並不需要保存和讀回一個枚舉,並選擇相應的不同的代碼路徑的優點,而是你提供你想要不同的處理每一個國家單獨的代碼。

+0

這個教訓是真正擺脫條件語句的唯一解決方案 - switch/case仍然是一個醜陋的條件語句(除非您正在編寫解析器)。 – 2012-02-07 00:27:13

0

二OO解決您的問題是狀態模式。它涉及用狀態對象封裝狀態交替條件。您可能會發現,關於模式herehere更多信息。順便說一句,如果你還沒有擁有它,我會強烈建議購買這本書。

乾杯!