我们有一些代码:
public class ErrorCodeUtil {
public static void handleErrorCode(String errorCode) {
if (errorCode.equals("1")) {
handleErrorCode1();
} else if (errorCode.equals("2")) {
handleErrorCode2();
} else if (errorCode.equals("3")) {
handleErrorCode3();
} else {
handleErrorCodeByDefault(errorCode);
}
}
public static void logByErrorCode(String errorCode) {
if (errorCode.equals("1")) {
logErrorCode1();
} else if (errorCode.equals("2")) {
logErrorCode2();
} else if (errorCode.equals("3")) {
logErrorCode3();
} else {
logErrorCodeByDefault(errorCode);
}
}
//... a lot of method about error code
}
如您所见,我们有Util
来处理ErrorCode
的所有内容,当我们想要为错误代码添加特殊逻辑时,我们必须更改该utils类的许多方法。
正如预期的那样,错误代码的值在很大范围内变化(可能是" 112345"或" error_code_001")。那么什么设计模式适用于那种情况呢?
答案 0 :(得分:3)
我会实现decision table。
该表将包含一个或多个Predicate
作为键和Function
作为值之间的一组映射。如果满足Predicate
条件,则执行相应的Function
。如果未满足Predicate
条件,则应执行默认Function
。这可以(轻松)取代巨大的" if-else"陈述,应该更容易维护。
Predicate
应该如何?它应该是String
(在您的情况下)并且应该返回boolean
,指示条件是否满足:
interface Predicate {
public boolean test(String x);
}
在决策表中,您将此接口的(匿名)实现添加为键。
提示:如果你已经使用Java8,那就更好了,那就是内置的Predicate<T>
接口。但如果您不是,那么您可以引入自己的Predicate
界面。 : - )
决策表值的Function
将是一个类似的界面。它可能(或可能不)使用输入参数并应返回void。在Java8中,这称为Consumer
,但在我的示例中,我将坚持Function
命名:
interface Function<T> {
void apply(T t);
}
通过在Predicate
作为键和Function<ErrorCodeUtil>
作为值之间构建对,我们将填充决策表。当满足Predicate
条件时,我们会调用相应的Function
.apply()
方法:
决策表本身可以是一个简单的Map<Predicate, Function<ErrorCodeUtil>>
:
Map<Predicate, Function<ErrorCodeUtil>> decisionTable = new HashMap<>();
你应该在施工时或任何你想要的地方填充它(就在handleErrorCode()
方法逻辑之前):
Predicate equalsOne = new Predicate() {
public void test(String x) {
return "1".equals(x);
}
};
Function<ErrorCodeUtil> actionOne = new Function<ErrorCodeUtil>() {
public void apply(ErrorCodeUtil t) {
t.handleErrorCode1();
}
}
decisionTable.put(equalsOne, actionOne);
等对于其他&#34;条件 - 动作&#34;对,包括else
将始终返回Predicate
的默认操作(即最后true
语句)。
请注意,在Java8中,只需使用lambdas就可以显着减少这些匿名类。
最后,你的&#34; if-elseif&#34;语句将被重新考虑到一个简单的循环:
for (Map.Entry<Predicate, Function<ErrorCodeUtil>> entry: decisionTable.entrySet()){
Predicate condition = entry.getKey();
Function<ErrorCodeUtil> action = entry.getValue();
if (condition.test(errorCode)) {
action.apply(this);
}
}
因此,每次添加新条件时,您都不必触及handleErrorCode(String error)
方法,但是您必须引入{{1}的新(匿名)实现}和Predicate
以及Function
将其放入决策表。
答案 1 :(得分:2)
在这种情况下我会使用Enum。
public enum ErrorCodeEnum {
1 {
@Override
public void handleErrorCode() {
//doSomething
}
},
2 {
@Override
public void handleErrorCode() {
//doSomething
}
};
public abstract void handleErrorCode();
}
然后,手中有错误代码......
ErrorCodeEnum.valueOf("1").handleErrorCode();
PS:正如你所问,这就是我用来替换if-else语句的方法。但我会针对该特定问题使用Logger API(似乎您正在记录错误)。
答案 2 :(得分:1)
您可以将列表中的所有错误代码保留在一个类中。并检查列表是否包含错误代码。
因此,这会降低您的if...else
逻辑。
您已编写了不同的方法来处理错误代码,例如handleErrorCode1()
,handleErrorCode2()
等。现在,如果列表包含所需的错误代码,那么您可以通过java反射调用这些方法。
答案 3 :(得分:0)
关于错误的记录,如果所需要的只是将代码与消息匹配,则具有代码到消息的映射的文本文件是正确的方式。文本文件可能是属性:
1=Item not Found
2=Item not valid
可以加载到java.util.Properties
实例,它可能是可以加载到DOM或HashMap中的xml
<errors>
<error>
<code>1</code>
<msg>Item not Found</msg>
</error>
<error>
<code>2</code>
<msg>Item not Valid</msg>
</error>
<errors>
这种方法的一个优点是,如果您在文件名中指定语言代码,然后从客户端获取用户语言代码,则可以使其支持i18n