bmu*_*uer 3 java refactoring switch-statement
我有一个我真的不喜欢的大开关盒,但我似乎没有找到一个优雅的替代解决方案。我们正在构建一个 JavaEE 平台,用户可以在其中创建项目。列出的方法用于确定向我们的用户显示的状态消息,这取决于许多因素,例如用户类型(我们有 2 个)、项目状态、项目的付款状态等等。这些因素中的大多数必须以编程方式确定,最终导致了这个大型 switch-case:
public List<String> getToDoMessages(Project project) {
UserAccount user = securitySession.getLoggedInAccount();
switch (user.getAccountType()) {
case EXPERT:
return getExpertToDoMessages(project, user);
case COMPANY:
return getCompanyToDoMessages(project, user);
default:
return new ArrayList<>();
}
}
private List<String> getCompanyToDoMessages(Project project, UserAccount user) {
List<String> ret = new ArrayList<>();
switch (project.getProjectState()) {
case OPEN_FOR_APPLICATION:
ret.add("projectToDo_company_applicationDeadlineNotPassed");
break;
case SELECT_APPLICATION:
ret.add("projectToDo_company_selectApplicant");
break;
case IN_PROGRESS:
ret.add("projectToDo_company_inProgress");
break;
case TEAM_PAYMENT_DISTRIBUTION:
ret.add("projectToDo_company_teamPaymentDistribution");
break;
case CONFIRM_INVOICES:
if (projectAssessmentService.hasAssessed(user, project)) {
ret.add("projectToDo_company_confirmInvoices");
} else {
ret.add("projectToDo_company_assessProject");
}
break;
default:
break;
}
return ret;
}
private List<String> getExpertToDoMessages(Project project, UserAccount user) {
ExpertPerson expert = securitySession.getExpert();
List<String> ret = new ArrayList<>();
switch (project.getProjectState()) {
case OPEN_FOR_APPLICATION:
if (projectService.hasAlreadyApplied(expert, project)) {
if (projectService.hasAlreadyAppliedAsPerson(expert, project)) {
ret.add("projectToDo_expert_appliedAsSinglePerson");
}
if (projectService.hasAlreadyAppliedAsTeam(expert, project)) {
ret.add("projectToDo_expert_appliedAsTeam");
}
} else {
if (projectService.canApply(expert, project)) {
ret.add("projectToDo_expert_openForApplication");
}
}
break;
case SELECT_APPLICATION:
ret.add("projectToDo_expert_selectApplicant");
break;
case IN_PROGRESS:
ret.add("projectToDo_expert_inProgress");
break;
case TEAM_PAYMENT_DISTRIBUTION:
Application application = project.getSelectedApplication();
if (application.isSingleApplication()) {
throw new IllegalStateException("Illegal state TEAM_PAYMENT_DISTRIBUTION for project that has selected a single application");
}
ExpertTeam team = application.getExpertTeam();
if (team.getLeader().equals(expert)) {
ret.add("projectToDo_expert_teamLeaderPaymentDistribution");
} else {
ret.add("projectToDo_expert_teamMemberPaymentDistribution");
}
break;
case CONFIRM_INVOICES:
if (projectAssessmentService.hasAssessed(user, project)) {
ret.add("projectToDo_expert_confirmInvoices");
} else {
ret.add("projectToDo_expert_assessProject");
}
break;
default:
break;
}
return ret;
}
Run Code Online (Sandbox Code Playgroud)
这个版本没有列出所有的可能性,例如项目类型的区别仍然缺失。当然,我至少可以将语句内的代码移动到单独的方法中,但我确信必须有一个更优雅的解决方案。有谁知道一个可能适用于这里的好模式?
提前致谢!
重构switch语句有 3 条好方法。
Map. 这允许您预先构建工具,通常甚至可以允许您从外部配置文件配置工具。这里的缺点是你必须跳过一些箍来添加逻辑。enum. 这可能比 a 更灵活,Map因为您可以在每个内部编写逻辑,enum但也有一些缺点。有些人认为 an 中的编码逻辑enum是一件坏事(我不认为)。此外,enums 只能是这一事实static会使您的工作变得不那么容易。Project对象具有getToDoMessages方法等。这可能会导致一些非常复杂的管理问题,因为所有getToDoMessages方法都分布在您的代码中,而不是像您现在拥有的那样分布在一个模块中 - 但请将此选项视为一个好的选项通常是最灵活的。Map路线示例:
Map<Integer,String> companyToDos = new HashMap<>();
static {
companyToDos.put(OPEN_FOR_APPLICATION, "projectToDo_company_applicationDeadlineNotPassed");
companyToDos.put(SELECT_APPLICATION, "projectToDo_company_selectApplicant");
companyToDos.put(IN_PROGRESS, "projectToDo_company_inProgress");
companyToDos.put(TEAM_PAYMENT_DISTRIBUTION, "projectToDo_company_teamPaymentDistribution");
companyToDos.put(CONFIRM_INVOICES_ASSESSED, "projectToDo_company_confirmInvoices");
companyToDos.put(CONFIRM_INVOICES_UNASSESSED, "projectToDo_company_assessProject");
}
Run Code Online (Sandbox Code Playgroud)
走enum路线的例子:
enum AccountType {
EXPERT{
@Override
List<String> getToDoMessages(Project project) {
return project.getState().getExpertToDoMessages();
}
},
COMPANY{
@Override
List<String> getToDoMessages(Project project) {
return project.getState().getCompanyToDoMessages();
}
};
abstract List<String> getToDoMessages(Project project);
}
enum ProjectState {
OPEN_FOR_APPLICATION{
@Override
List<String> getExpertToDoMessages(Project project) {
return ...
}
@Override
List<String> getCompanyToDoMessages(Project project) {
return ...
}
},
SELECT_APPLICATION{
@Override
List<String> getExpertToDoMessages(Project project) {
return ...
}
@Override
List<String> getCompanyToDoMessages(Project project) {
return ...
}
};
abstract List<String> getExpertToDoMessages(Project project);
abstract List<String> getCompanyToDoMessages(Project project);
}
Run Code Online (Sandbox Code Playgroud)