Java枚举或其他集合

问题描述:

我们目前有两个客户代码“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

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

+0

如果你真的同意,*为什么*你在寻找Java的替代品? – EJP

假设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

如果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

由于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。)

枚举不好,因为枚举的所有实例都必须有相同的方法。

即使使用类型的枚举感觉可能是错误的,因为你将有效地做instanceof,这通常是一种设计气味。

我想你已经有了传承的经典案例:

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

尝试抽象的方法,在基类常见的抽象行为。