- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
我必须重构庞大的现有代码。在 SO 和其他站点上经历了很多类似的问题,仍然感到困惑。如果有人能提出一些建议或任何想法都会有很大帮助。
有 5 个下拉菜单,我需要根据下拉菜单中的选定值更新 View 。第一个下拉菜单有以下选项:
"TOP DOWN BUDGET"
"TEMPLATE BUDGET"
"ORIGINAL BUDGET"
"REVISED BUDGET"
第二个下拉菜单有以下选项:
"Day"
"Week"
"Month"
"Quarter"
"Year"
第三个下拉菜单有以下选项:
"Details"
"Summary"
第四个下拉菜单有以下选项:
"Hours"
"Dollars"
第五个下拉菜单有以下选项:
"StartDate"
"EndDate"
现在代码有以下场景:
public List<WorkPlanReport> XYZ(...){//opening of some method XYZ....
List<WorkPlanReport> workPlanReportList=null;
switch(first_Drop_Down_Value){
case "TOP DOWN BUDGET":
List<TaskDetails> timeLine=getTimeLine("firstDropDownA", second_drop_down_val, third_drop_down_val, fourth_drop_down_val);
workPlanReportList=setWorkPlanByTimeLine(timeLine, "firstDropDownA", second_drop_down_val, third_drop_down_val, fourth_drop_down_val);
break;
case "TEMPLATE BUDGET":
List<TaskDetails> timeLine=getTimeLine("firstDropDownB", second_drop_down_val, third_drop_down_val, fourth_drop_down_val, fifth_dd_val);
workPlanReportList=setWorkPlanByTimeLine(timeLine, "firstDropDownA", second_drop_down_val, third_drop_down_val, fourth_drop_down_val);
break;
case "ORIGINAL BUDGET":
List<TaskDetails> timeLine=getTimeLine("firstDropDownC", second_drop_down_val, third_drop_down_val, fourth_drop_down_val, fifth_dd_val);
workPlanReportList=setWorkPlanByTimeLine(timeLine, "firstDropDownA", second_drop_down_val, third_drop_down_val, fourth_drop_down_val);
break;
case "REVISED BUDGET":
List<TaskDetails> timeLine=getTimeLine("firstDropDownD", second_drop_down_val, third_drop_down_val, fourth_drop_down_val, fifth_dd_val);
workPlanReportList=setWorkPlanByTimeLine(timeLine, "firstDropDownA", second_drop_down_val, third_drop_down_val, fourth_drop_down_val);
break;
}
return workPlanReportList;
}// Closing of some method XYZ....
private List<TaskDetails> getTimeLine(String first_Drop_Down_Value, String second_dd_val, third_dd_val, fourth_dd_val, String fifth_dd_val){
switch(second_Drop_Down_Value){
case "Day":
if(third_dd_val.equals("Details")){
if(fourth_dd_val.equals("Hours")){
if(fifth_dd_val.equals("startDate"){
//prepare query & call DB for fetching days timeline for hours details of TOP DOWN BUDGET filtered by start date...
}
else// means endDate{
//prepare query & call DB for fetching days timeline for hours details of TOP DOWN BUDGET filtered by end date...
}
}
else{//means Dollars
if(fifth_dd_val.equals("startDate"){
//prepare query & call DB for fetching days timeline for dollars details of TOP DOWN BUDGET filtered by start date...
}
else// means endDate{
//prepare query & call DB for fetching days timeline for dollars details of TOP DOWN BUDGET filtered by end date...
}
}
}
else// means summary...
{
if(fourth_dd_val.equals("Hours")){
if(fifth_dd_val.equals("startDate"){
//prepare query & call DB for fetching days timeline for 'hours' "summary" of TOP DOWN BUDGET filtered by start date...
}
else// means endDate{
//prepare query & call DB for fetching days timeline for hours summary of TOP DOWN BUDGET filtered by end date...
}
}
else{//means Dollars
if(fifth_dd_val.equals("startDate"){
//prepare query & call DB for fetching days timeline for dollars details of TOP DOWN BUDGET filtered by start date...
}
else// means endDate{
//prepare query & call DB for fetching days timeline for dollars details of TOP DOWN BUDGET filtered by end date...
}
}
}
break;
case "Week":
//....similar code as in case "Day" just here we need to fetch data week-wise
break;
case "Month":
//....similar code as in case "Day" just here we need to fetch data month-wise
break;
case "Quarter":
//....similar code as in case "Day" just here we need to fetch data quarter-wise
break;
case "Year":
//....similar code as in case "Day" just here we need to fetch data year-wise
break;
}
}
private List<WorkPlanReport> setWorkPlanByTimeLine(List<TaskDetails> timeLine, String "firstDropDownA", String second_drop_down_val, String third_drop_down_val, String fourth_drop_down_val){
WorkPlanReport wpr=new WorkPlanReport();
// Here I have real mess..., Iterating the timeLine list and have switch case and inside switch case multilevel nesting of if else to decide which setter we need to use to set the value.
for example:
If it is "TOP DOWN BUDGET" in first drop-down, "Day" in second drop-down, "Details" in third drop down, "Hours" in fourth drop-down & "StartDate" in fifth drop-down, I have to call follwing code:
wpr.setTDBDetailsHoursByStartDate(taskDetails.getTDBDetailsByHourStartDayView());
If it is "TOP DOWN BUDGET" in first drop-down, "Day" in second drop-down, "Details" in third drop down, "Hours" in fourth drop-down & "EndDate" in fifth drop-down, I have to call follwing code:
wpr.setTDBDetailsHoursByEndDate(taskDetails.getTDBDetailsByHourEndDayView());
这段代码超过 1000 行,我很想用一些合适的设计模式重构它。
WorkPlanReport 和 TaskDetails DTO 有一些相似类型的共同属性,还有许多其他不同的属性。
我不允许更改那些 DTO,因为它们在一些相关的公共(public)代码库中使用。
编辑:这是此代码中使用的方法。我尽力使关卡变得简单,但无法想出任何可行的想法。
private void setSummaryColumns(String DolOrHr, String columnFilter,
Map<String, String> filterBy, Object[] obj,
WorkplanReport workplanReport, TemplateDump td) {
switch(filterBy.get(columnFilter)){
case "TOP DOWN":
td.setTopDownBudgetStartDate(obj[1] != null ? (Date)obj[1]:null);
td.setTopDownBudgetEndDate(obj[2] != null ? (Date)obj[2]:null);
workplanReport.setStartDatebyMajorMeasure(obj[1] != null ? obj[1].toString():"-");
workplanReport.setEndDatebyMajorMeasure(obj[2] != null ? obj[2].toString():"-");
workplanReport.setDolorHrsbyMajorMeasure(obj[3] != null ? obj[3].toString():"-");
if(DolOrHr.equals("BudgetDollars"))
td.setTopDownBudgetDollars(obj[3] != null ? (BigDecimal)obj[3]:null);
else
td.setTopDownBudgetHours(obj[3] != null ? (BigDecimal)obj[3]:null);
break;
case "TEMPLATE":
td.setTemplateBudgetStartDate(obj[1] != null ? (Date)obj[1]:null);
td.setTemplateBudgetEndDate(obj[2] != null ? (Date)obj[2]:null);
workplanReport.setStartDatebyTemplateBudget(obj[1] != null ? obj[1].toString():"-");
workplanReport.setEndDatebyTemplateBudget(obj[2] != null ? obj[2].toString():"-");
workplanReport.setDolorHrsbyTemplateBudget(obj[3] != null ? obj[3].toString():"-");
if(DolOrHr.equals("BudgetDollars"))
td.setTemplateBudgetDollars(obj[3] != null ? (BigDecimal)obj[3]:null);
else
td.setTemplateBudgetHours(obj[3] != null ? (BigDecimal)obj[3]:null);
break;
case "ORIGINAL":
td.setOriginalBudgetStartDate(obj[1] != null ? (Date)obj[1]:null);
td.setOriginalBudgetEndDate(obj[2] != null ? (Date)obj[2]:null);
workplanReport.setOrgStartDate(obj[1] != null ? obj[1].toString():"-");
workplanReport.setOrgEndDate(obj[2] != null ? obj[2].toString():"-");
workplanReport.setOrgBudgetedDollarsHours(obj[3] != null ? obj[3].toString():"-");
if(DolOrHr.equals("BudgetDollars"))
td.setOriginalBudgetDollars(obj[3] != null ? (BigDecimal)obj[3]:null);
else
td.setOriginalBudgetHours(obj[3] != null ? (BigDecimal)obj[3]:null);
break;
case "REVISED":
td.setRevisedBudgetStartDate(obj[1] != null ? (Date)obj[1]:null);
td.setRevisedBudgetEndDate(obj[2] != null ? (Date)obj[2]:null);
workplanReport.setRevStartDate(obj[1] != null ? obj[1].toString():"-");
workplanReport.setRevEndDate(obj[2] != null ? obj[2].toString():"-");
workplanReport.setRevBudgetedDollarsHours(obj[3] != null ? obj[3].toString():"-");
if(DolOrHr.equals("BudgetDollars"))
td.setRevisedBudgetDollars(obj[3] != null ? (BigDecimal)obj[3]:null);
else
td.setRevisedBudgetHours(obj[3] != null ? (BigDecimal)obj[3]:null);
break;
case "MANAGER":
td.setManagerBudgetStartDate(obj[1] != null ? (Date)obj[1]:null);
td.setManagerBudgetEndDate(obj[2] != null ? (Date)obj[2]:null);
workplanReport.setStartDatebyManagersRevised(obj[1] != null ? obj[1].toString():"-");
workplanReport.setEndDatebyManagersRevised(obj[2] != null ? obj[2].toString():"-");
workplanReport.setDolorHrsbyManagersRevised(obj[3] != null ? obj[3].toString():"-");
if(DolOrHr.equals("BudgetDollars"))
td.setManagerBudgetDollars(obj[3] != null ? (BigDecimal)obj[3]:null);
else
td.setManagerBudgetHours(obj[3] != null ? (BigDecimal)obj[3]:null);
break;
case "ACTUAL":
td.setActualBudgetStartDate(obj[1] != null ? (Date)obj[1]:null);
td.setActualBudgetEndDate(obj[2] != null ? (Date)obj[2]:null);
workplanReport.setStartDatebyActual(obj[1] != null ? obj[1].toString():"-");
workplanReport.setEndDatebyActual(obj[2] != null ? obj[2].toString():"-");
workplanReport.setDolorHrsbyActual(obj[3] != null ? obj[3].toString():"-");
if(DolOrHr.equals("BudgetDollars"))
td.setActualBudgetDollars(obj[3] != null ? (BigDecimal)obj[3]:null);
else
td.setActualBudgetHours(obj[3] != null ? (BigDecimal)obj[3]:null);
break;
}
}
最佳答案
你在实际代码中重复了很多东西。
在考虑您可以使用的模式之前,我建议您开始消除实际的真正的问题:作为反模式的代码重复。
minor dup 是第一级 switch
语句:
case "TOP DOWN BUDGET":
List<TaskDetails> timeLine=getTimeLine("firstDropDownA", second_drop_down_val, third_drop_down_val, fourth_drop_down_val);
workPlanReportList=setWorkPlanByTimeLine(timeLine, "firstDropDownA", second_drop_down_val, third_drop_down_val, fourth_drop_down_val);
break;
case "TEMPLATE BUDGET":
List<TaskDetails> timeLine=getTimeLine("firstDropDownB", second_drop_down_val, third_drop_down_val, fourth_drop_down_val, fifth_dd_val);
workPlanReportList=setWorkPlanByTimeLine(timeLine, "firstDropDownA", second_drop_down_val, third_drop_down_val, fourth_drop_down_val);
break;
...
几乎所有的都是重复的。单一变体是传递给 getTimeLine()
的第一个参数。
用 Budget
枚举替换您在 switch
语句中使用的字符串,这部分也可以缩短为:
Budget budget = Budget.valueOf(first_Drop_Down_Value);
List<TaskDetails> timeLine=getTimeLine(budget.getValueForTimeLine(), second_drop_down_val, third_drop_down_val, fourth_drop_down_val);
workPlanReportList=setWorkPlanByTimeLine(timeLine, "firstDropDownA", second_drop_down_val, third_drop_down_val, fourth_drop_down_val);
而且看起来大重复位于 getTimeLine()
中。
您可以为您复制的每件东西应用完全相同的配方,其中唯一真正的差异是您可以传递的参数。
因此,不是打开第二个下拉菜单的可能性(“Day”"Week","Month","Quarter","Year") 引入一个枚举来传达这些信息:
TimePeriod timePeriod = TimePeriod.valueOf(second_Drop_Down_Value);
对第三个下拉菜单(“详细信息”和“摘要”)执行相同的操作:
DetailLevel detailLevel = DetailLevel.valueOf(third_Drop_Down_Value);
然后给出一种方法,根据选择的TimePeriod
和DetailLevel
改变fetch的粒度。它只是在检索数据的方法中传递的两个参数。
通过在此处停止您的重构任务,getTimeLine()
看起来真的更短更简单了:
private List<TaskDetails> getTimeLine(String first_Drop_Down_Value, String second_dd_val, third_dd_val, fourth_dd_val, String fifth_dd_val){
TimePeriod timePeriod = TimePeriod.valueOf(second_Drop_Down_Value);
DetailLevel detailLevel = DetailLevel.valueOf(third_Drop_Down_Value);
if(fourth_dd_val.equals("Hours")){
if(fifth_dd_val.equals("startDate"){
fetch(...,....,timePeriod, detailLevel) // <- pass the enums
}
else// means endDate{
//prepare query & call DB for fetching days timeline for hours details of TOP DOWN BUDGET filtered by end date...
fetch(...,....,timePeriod, detailLevel) // <- pass the enums
}
}
else{//means Dollars
if(fifth_dd_val.equals("startDate"){
//prepare query & call DB for fetching days timeline for dollars details of TOP DOWN BUDGET filtered by start date...
fetch(...,....,timePeriod, detailLevel) // <- pass the enums
}
else// means endDate{
//prepare query & call DB for fetching days timeline for dollars details of TOP DOWN BUDGET filtered by end date...
fetch(...,....,timePeriod, detailLevel) // <- pass the enums
}
}
}
编辑
关于在 switch
语句的情况下调用不同的 setter 的部分,您仍然有许多相似之处,您可以找出这些相似之处。
以案例为例:“TOP DOWN”和“ORIGINAL”:
td.setTopDownBudgetStartDate(obj[1] != null ? (Date)obj[1]:null);
td.setTopDownBudgetEndDate(obj[2] != null ? (Date)obj[2]:null);
对比
td.setOriginalBudgetStartDate(obj[1] != null ? (Date)obj[1]:null);
td.setOriginalBudgetEndDate(obj[2] != null ? (Date)obj[2]:null);
然后:
workplanReport.setStartDatebyMajorMeasure(obj[1] != null ? obj[1].toString():"-");
workplanReport.setEndDatebyMajorMeasure(obj[2] != null ? obj[2].toString():"-");
workplanReport.setDolorHrsbyMajorMeasure(obj[3] != null ? obj[3].toString():"-");
对比:
workplanReport.setOrgStartDate(obj[1] != null ? obj[1].toString():"-");
workplanReport.setOrgEndDate(obj[2] != null ? obj[2].toString():"-");
workplanReport.setOrgBudgetedDollarsHours(obj[3] != null ? obj[3].toString():"-");
所以...
最后,应用相同的逻辑,但计算没有分配给 WorkPlanReport
和 TemplateDump
对象中的相同 setter 。WorkPlanReport
和 TemplateDump
显示为具有许多单独字段的类,这些字段可以甚至应该提取到特定类中,因为它们之间是相关的:这是高内聚原则.
例如对于“TOP DOWN”转储,您可以定义:
public class TopDownTemplateDump {
private Date budgetStartDate;
private Date budgetEndDate;
private BigDecimal budgetDollars;
private BigDecimal budgetHours;
// and so for ...
// setters - getters
}
对于“原始”转储,您可以定义:
public class OriginalTemplateDump {
private Date budgetStartDate;
private Date budgetEndDate;
private BigDecimal budgetDollars;
private BigDecimal budgetHours;
// and so for ...
// setters - getters
}
保存每个“转储部分”的 TemplateDump
现在看起来像这样:
public class TemplateDump {
private TopDownTemplateDump topDownTemplateDump;
private OriginalTemplateDump originalTemplateDump;
...
}
但是复制所有这些“转储”类而它们将拥有完全相同的结构是否有意义?不是真的。
您可能应该将它们提取到一个基类中:
public abstract class AbstractTemplateDump {
private Date budgetStartDate;
private Date budgetEndDate;
private BigDecimal budgetDollars;
private BigDecimal budgetHours;
// and so for ...
// setters - getters
}
具体部分现在可以从 AbstractTemplateDump
继承,例如:
public class TopDownTemplateDump extends AbstractTemplateDump{
// add subclass specifities here
}
现在您有一个统一的方法来设置 TemplateDump
实例的数据。因此,不再需要 switch
。
遵循 WorkPlanReport
完全相同的逻辑。
您的代码现在可能如下所示:
AbstractTemplateDump absTd = td.getDumpPart(filterBy.get(columnFilter));
AbstractReportPart absRp = workplanReport.getReportPart(filterBy.get(columnFilter));
absTd.setBudgetStartDate(obj[1] != null ? (Date)obj[1]:null);
absTd.setBudgetEndDate(obj[2] != null ? (Date)obj[2]:null);
absRp.setStartDateby(obj[1] != null ? obj[1].toString():"-");
absRp.setEndDateby(obj[2] != null ? obj[2].toString():"-");
absRp.setDolorHrsby(obj[3] != null ? obj[3].toString():"-");
// ...
关于java - 使用嵌套 if else 和 switch 语句重构代码的设计模式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51557162/
对此感到疯狂,真的缺少一些东西。 我有webpack 4.6.0,webpack-cli ^ 2.1.2,所以是最新的。 在文档(https://webpack.js.org/concepts/mod
object Host "os.google.com" { import "windows" address = "linux.google.com" groups = ["linux"] } obj
每当我安装我的应用程序时,我都可以将数据库从 Assets 文件夹复制到 /data/data/packagename/databases/ .到此为止,应用程序工作得很好。 但 10 或 15 秒后
我在 cc 模式缓冲区中使用 hideshow.el 来折叠我不查看的文件部分。 如果能够在 XML 文档中做到这一点就好了。我使用 emacs 22.2.1 和内置的 sgml-mode 进行 xm
已结束。此问题不符合 Stack Overflow guidelines .它目前不接受答案。 我们不允许提出有关书籍、工具、软件库等方面的建议的问题。您可以编辑问题,以便用事实和引用来回答它。 关闭
根据java: public Scanner useDelimiter(String pattern) Sets this scanner's delimiting pattern to a patt
我读过一些关于 PRG 模式以及它如何防止用户重新提交表单的文章。比如this post有一张不错的图: 我能理解为什么在收到 2xx 后用户刷新页面时不会发生表单提交。但我仍然想知道: (1) 如果
看看下面的图片,您可能会清楚地看到这一点。 那么如何在带有其他一些 View 的简单屏幕中实现没有任何弹出/对话框/模式的微调器日期选择器? 我在整个网络上进行了谷歌搜索,但没有找到与之相关的任何合适
我不知道该怎么做,我一直遇到问题。 以下是代码: rows = int(input()) for i in range(1,rows): for j in range(1,i+1):
我想为重写创建一个正则表达式。 将所有请求重写为 index.php(不需要匹配),它不是以/api 开头,或者不是以('.html',或'.js'或'.css'或'.png'结束) 我的例子还是这样
MVC模式代表 Model-View-Controller(模型-视图-控制器) 模式 MVC模式用于应用程序的分层开发 Model(模型) - 模型代表一个存取数据的对象或 JAVA PO
我想为组织模式创建一个 RDF 模式世界。您可能知道,组织模式文档基于层次结构大纲,其中标题是主要的分组实体。 * March auxiliary :PROPERTIES: :HLEVEL: 1 :E
我正在编写一个可以从文件中读取 JSON 数据的软件。该文件包含“person”——一个值为对象数组的对象。我打算使用 JSON 模式验证库来验证内容,而不是自己编写代码。符合代表以下数据的 JSON
假设我有 4 张 table 人 公司 团体 和 账单 现在bills/persons和bills/companys和bills/groups之间是多对多的关系。 我看到了 4 种可能的 sql 模式
假设您有这样的文档: doc1: id:1 text: ... references: Journal1, 2013, pag 123 references: Journal2, 2014,
我有这个架构。它检查评论,目前工作正常。 var schema = { id: '', type: 'object', additionalProperties: false, pro
这可能很简单,但有人可以解释为什么以下模式匹配不明智吗?它说其他规则,例如1, 0, _ 永远不会匹配。 let matchTest(n : int) = let ran = new Rand
我有以下选择序列作为 XML 模式的一部分。理想情况下,我想要一个序列: 来自 my:namespace 的元素必须严格解析。 来自任何其他命名空间的元素,不包括 ##targetNamespace和
我希望编写一个 json 模式来涵盖这个(简化的)示例 { "errorMessage": "", "nbRunningQueries": 0, "isError": Fals
首先,我是 f# 的新手,所以也许答案很明显,但我没有看到。所以我有一些带有 id 和值的元组。我知道我正在寻找的 id,我想从我传入的三个元组中选择正确的元组。我打算用两个 match 语句来做到这
我是一名优秀的程序员,十分优秀!