5

我们目前有两个客户代码“CUSTA”和“CUSTA”。CUSTA 可以执行操作 A1、A2、A3、A4、A5、A6。CUTB 可以根据某些条件执行操作 B1、B2、B3、B4、B5、B6。目前他们不期待更多的客户代码,但我希望设计灵活。这些可以存储在数据库中,但正如我所提到的,因为很长一段时间内不太可能有另一个客户代码,它需要用代码表示。

应用程序逻辑基本算法看起来像

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”、“CUSTA”、“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}

我应该创建一个Mapwhere 键是 CustomerCode 并添加相应的操作作为值。

解决这个问题的最佳解决方案是什么。例如,将来添加“CUSTC”也应该是灵活的。

谢谢

4

5 回答 5

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();
    }
  }
}
于 2013-09-30T23:47:44.440 回答
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)并具有接口的EnumMapCustomerCode到实例。(每个操作可能有一个EnumMap。)

于 2013-09-30T23:54:08.167 回答
0

我会把整个事情变成数据库中的查找表,并尽可能少地编写代码。它可能会或可能不会改变,但即使它没有改变,它对每个人来说都会更有意义。

于 2013-09-30T23:45:35.313 回答
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;
        }
    }
}

这是否适合您正在尝试做的事情?

当然,如果您要使用枚举,那么当您获得新的客户类型时,您必须更新代码,但无论如何您可能都必须更新代码。另一种可能更好的方法是定义接口并使用工厂模式。它可能会更干净:

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 */
    }
}

我要添加的最后一件事是,您可以添加 Customer 的实现,只要它们在您的类路径上,就无需更改代码即可加载,那就是使用反射并将类名传递给工厂:

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!");
    }
}
于 2013-09-30T23:47:24.050 回答
0

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

即使对类型使用枚举也可能是错误的,因为您将有效地执行 instanceof,这通常是一种设计气味。

我认为你有一个经典的继承案例:

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

尝试将您的方法抽象为基类中的常见抽象行为。

于 2013-10-01T00:03:34.110 回答