我们目前有两个客户代码“CUSTA”和“CUSTB”。 CUSTA可以执行操作A1,A2,A3,A4,A5,A6。 CUSTB可以根据某些条件执行操作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”,“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
,其中key是CustomerCode,并将相应的操作添加为值。
解决此问题的最佳解决方案是什么。此外,例如,在未来添加“CUSTC”也应该是灵活的。
由于
答案 0 :(得分: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();
}
}
}
答案 1 :(得分: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()
。
一种非常不同的方法是将操作定义为接口(例如,Runnable
或Callable
)并从EnumMap
获得CustomerCode
到接口的实例。 (每个操作可能有一个EnumMap
。)
答案 2 :(得分:0)
我会在数据库中创建一个查找表,并尽可能少地编写代码。它可能会也可能不会改变,但即使它没有改变,它也会让每个人都更有意义。
答案 3 :(得分: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 */
}
}
我要添加的最后一件事就是让你添加Customer的实现,只要它们在你的类路径上就加载而不加代码更改是使用反射并将类名传递给Factory:
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!");
}
}
答案 4 :(得分:0)
枚举并不好,因为枚举的所有实例都必须具有相同的方法。
即使使用类型的枚举也可能是错误的,因为你实际上会做一个设计气味的instanceof。
我认为你有一个经典的继承案例:
public abstract class Customer {
// common code
}
public class CustomerA extends Customer {
// specific/decorated behaviour
}
public class CustomerB extends Customer {
// specific/decorated behaviour
}
尝试将您的方法抽象为基类中的常见抽象行为。