2013-09-30 90 views
5

我們目前有兩個客戶代碼「CUSTA」和「CUSTB」。 CUSTA可以執行操作A1,A2,A3,A4,A5,A6。 CUSTB可以根據一些條件執行操作B1,B2,B3,B4,B5,B6。目前他們並不期待更多的客戶代碼,但我希望設計具有靈活性。這些可以存儲在數據庫中,但正如我所提到的,因爲長時間不可能擁有另一個客戶代碼,它需要用代碼表示。Java枚舉或其他集合

應用邏輯基本算法看起來像

if ConditionX is true 
then if customerCode is "CUSTA" 
    then applicableOperation = 'A1' 
    else 
     if customerCode is "CUSTB" 
     then applicableOperation = 'B1' 
     end 
else 
    if ConditionY is true  
    then 
     if customerCode is "CUSTA" 
     then applicableOperation = 'A2' 
     else 
      if customerCode is "CUSTB" 
       then applicableOperation = 'B2' 
      end 
     else 

............... ................ 。

我可以編寫switch語句等來清理算法,但我主要關心的是如何表示「CUSTA」,「CUSTB」,「A1」,「A2」,「A3」,「A4」。 .. 「A6」, 「B1」, 「B2」 ... 「B6」。客戶是否碼是枚舉像

public enum CustomerCode { CUSTA, CUSTB } 
public enum OperationsForA{ A1, A2, A3,...A6 } 
public enum OperationsForB{ B1, B2, B3...B6} 

我應當創造一個Map,其中關鍵是CustomerCode,並添加相應的操作作爲值。

什麼是最好的解決方案來解決這個問題。例如,未來還應該靈活地添加「CUSTC」。

感謝

回答

0

我會使整個事情在數據庫中查找表,並編寫儘可能少的代碼越好。它可能會也可能不會改變,但即使它不會,每個人都會更有意義。

+0

我同意..但我正在尋找Java的替代品。 –

+0

如果你真的同意,*爲什麼*你在尋找Java的替代品? – EJP

0

假設A1相似,B1等,我會實現它這樣的,給他們同樣的操作名稱:

public enum Customer { 
    CUSTA, CUSTB; 

    public void operation1(){ 
     switch(this){ 
     case CUSTA: 
      // do A thing; 
      break; 
     case CUSTB: 
      // do it the B way 
      break; 
     } 
    } 
} 

能配合到你想要做什麼?

當然,如果你要使用枚舉,那麼當你得到一個新的Customer類型時,你將不得不更新代碼,但是你可能不得不更新代碼。另一種可能更好的方法是定義一個接口並使用Factory模式;它可能會來了清潔:

public interface Customer { 
    void operation1(); 
} 

class CustomerFactory{ 
    public static Customer getByName(String cust){ 
     if(cust.equals("CUSTA")){ 
      return new CustomerA(); 
     } 
     if(cust.equals("CUSTB")){ 
      return new CustomerB(); 
     } 
     throw new IllegalArgumentException(
       "Customer type " + cust + " not supported."); 
    } 
} 

class CustomerA implements Customer{ 
    @Override 
    public void operation1(){ 
     /* A's implementation */ 
    } 
} 

class CustomerB implements Customer{ 
    @Override 
    public void operation1(){ 
     /* B's implementation */ 
    } 
} 

我想補充一點,就會讓你添加客戶的實現,這將不加載代碼的最後一件事改變,只要它們在你的類路徑是使用反射,並通過課堂名工廠:

package test; 

import java.lang.reflect.Constructor; 
import java.lang.reflect.InvocationTargetException; 

public class CustomerTest{ 
    public static void main(String[] arg){ 
     CustomerFactory.getByName("test.CustomerA").operation1(); 
     CustomerFactory.getByName("test.CustomerB").operation1(); 
     CustomerFactory.getByName("test.CustomerC").operation1(); 
    } 
} 
interface Customer { 
    void operation1(); 
} 

class CustomerFactory{ 
    public static Customer getByName(final String cust){ 
     try{ 
      Class<? extends Customer> customerSubclass 
       = Class.forName(cust).asSubclass(Customer.class); 

      Constructor<? extends Customer> constructor 
       = customerSubclass.getDeclaredConstructor(new Class[0]); 

      return constructor.newInstance(new Object[0]); 
     } catch(ClassNotFoundException e){ 
      System.err.println("Trouble finding .class file for class "+cust+". "+e); 
     } catch(ClassCastException e){ 
      System.err.println("Found .class file for "+cust+" but it doesn't implement Customer."+" "+e); 
     } catch(NoSuchMethodException e){ 
      System.err.println("Class "+cust+" doesn't provide a no-arg constructor. :("+" "+e); 
     } catch(IllegalAccessException e){ 
      System.err.println("No-arg constructor isn't accessible. :("+" "+e); 
     } catch(InstantiationException e){ 
      System.err.println("Couldn't instantiate?"+" "+e); 
     } catch(InvocationTargetException e){ 
      System.err.println("Umm... something else broke."+" "+e); 
     } 
     throw new IllegalArgumentException(
       "Customer type " + cust + " not supported."); 
    } 
} 

class CustomerA implements Customer{ 
    @Override 
    public void operation1(){ 
     /* A's implementation */ 
     System.out.println("I'm an A doing operation1!"); 
    } 
} 

class CustomerB implements Customer{ 
    @Override 
    public void operation1(){ 
     /* B's implementation */ 
     System.out.println("I'm a B doing operation1!"); 
    } 
} 
+1

對於第一種方法,在頂層將'operation1'聲明爲抽象方法,然後爲每個枚舉常量實現方法好得多。 –

+0

這不是一個壞主意,但它也取決於實現的相似或不同。沒有進一步的細節,很難知道採取哪種方法。 +1雖然。 – UFL1138

4

如果A1對應B1,A2對應B2,等等,那麼你需要polymorphism

這意味着您將擁有一個通用的CustomerOperations接口。每個客戶代碼將創建CustomerOperations接口的具體實施,並將相應的正確操作返回到Condition X,Condition Y等。

設置您的接口:

interface CustomerOperations { 
    Operation operationForX(); 
    Operation operationForY(); 
} 

interface Operation { 
    Result someMethod(); 
} 

設置您的枚舉和實現的接口:

enum OperationsForA implements Operation { 
    A1, A2, A3; 
    // Implement someMethod 
} 

enum OperationsForB implements Operation { 
    B1, B2, B3; 
    // Implement someMethod 
} 

enum CustomerCode implements CustomerOperations { 
    CUSTA { 
    Operation operationForX() { 
     return OperationsForA.A1; 
    } 
    Operation operationForY() { 
     return OperationsForA.A2; 
    } 
    }, 

    CUSTB { 
    Operation operationForX() { 
     return OperationsForB.B1; 
    } 
    Operation operationForY() { 
     return OperationsForB.B2; 
    } 
    } 
    ; 
} 

用法示例:(這是那裏的多態性發生)

public class Main { 
    public static void main(String... args) { 
    CustomerOperations operator = CustomerOperations.CUSTA; 

    if (conditionX) { 
     // Could be inlined, but I've separated it for type readability: 

     // Get the appropriate operation from the operator. 
     Operation thingToDoForX = operator.operationForX(); 

     // Run the operation and get the result 
     Result result = thingToDoForX.someMethod(); 
    } 
    } 
} 
+0

+1這是完美的靈活性。過去我看到過於複雜的設計,因爲他們努力靈活地適應從未發生的變化。在Java中保持這種邏輯可以更容易地進行更改,但如果不更改,則很少丟失。 – Brandon

1

由於enum值是Java類,你可以做這樣的事情:

public enum CustomerCode { 
    CUSTA { 
     @Override 
     public void op1() { 
      // operation A1 implementation 
     } 
     @Override 
     public void op2() { 
      // operation A2 implementation 
     } 
     // etc. 
    }, 
    CUSTB { 
     @Override 
     public void op1() { 
      // operation B1 implementation 
     } 
     // etc. 
    }; 
    public abstract void op1(); 
    public abstract void op2(); 
    // etc. 
} 

那麼你的應用程序邏輯可能是這樣的:

CustomerCode customerCode = . . .; 
if (conditionX()} { 
    customerCode.op1(); 
} else if (conditionY()) { 
    customerCode.op2(); 
} // etc. 

如果這是有道理的建築,你可以移動if...else鏈內枚舉代碼;在這種情況下,您可能只需要一種方法:doApplicableOperation()

甲非常不同的方法是定義的操作的接口(例如,RunnableCallable),並具有從一個CustomerCodeEnumMap到接口的實例。 (每個操作可能有一個EnumMap。)

0

枚舉不好,因爲枚舉的所有實例都必須有相同的方法。

即使使用類型的枚舉感覺可能是錯誤的,因爲你將有效地做instanceof,這通常是一種設計氣味。

我想你已經有了傳承的經典案例:

public abstract class Customer { 
    // common code 
} 
public class CustomerA extends Customer { 
    // specific/decorated behaviour 
} 
public class CustomerB extends Customer { 
    // specific/decorated behaviour 
} 

嘗試抽象的方法,在基類常見的抽象行爲。