- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
我有以下伪代码
using (some web service/disposable object)
{
list1 = service.get1();
list2 = service.get2();
for (item2 in list2)
{
list3 = service.get3(depending on item2);
for (item3 in list3)
{
list4 = service.get4(depending on item3 and list1);
for (item4 in list4)
{
...
}
}
}
}
整个代码有 500 行,其中包含 for
语句中的大量逻辑。问题是将其重构为可读和可维护的代码,并作为类似情况的最佳实践。以下是我目前找到的可能解决方案。
1:拆分成方法考虑到我们将每个 for
提取到它自己的方法中,以提高可读性,我们最终得到 method2、method3 和 method4。每个方法都有自己的参数和依赖关系,这很好,除了 method4。 Method4 依赖于 list1,这意味着 list1 也必须传递给方法 2 和 3。在我看来,这变得不可读了。任何查看 method2 的开发人员都会意识到其中的 list1 没有意义,因此他必须向下查看链,直到 method4 才能真正意识到依赖 -> 低效。那么,如果 list4 或 item4 发生变化并且不再需要依赖 list1 会发生什么?我必须删除方法 4 的 list1 参数(当然应该这样做),但也必须删除方法 2 和 3 的参数(超出更改范围)-> 再次效率低下。另一个副作用是,在很多依赖和多层次的情况下,传递的参数数量会迅速增加。想想如果 list4 还依赖于 list11、list12 和 list13,它们都是在 list1 级别创建的,会发生什么情况。
2:保持长单方法优点是每个列表和项目都可以访问每个父列表和项目,这使得进一步的更改成为一行。如果 list4 不再依赖于 list1,只需删除/替换代码,而无需更改任何其他内容。显然,问题在于该方法是几百行,我们都知道这不好。
<强>3。两全其美?这个想法是只将每个 for
的内部逻辑部分拆分为方法。这样 main 方法将减少,我们获得可读性和可能的可维护性。将 for
留在 main 方法中,我们仍然能够将每个依赖项作为一行来访问。我们最终得到这样的结果:
for (item2 in list2)
{
compute();
list3 = service.get3(depending on item2);
for (item3 in list3)
{
compute(item2, eventually item1)
list4 = service.get4(depending on item3 and list1);
for (item4 in list4)
{
...
}
}
}
但是还有一个问题。您如何命名这些compute
方法以便于阅读?假设我有一个局部变量 instanceA
或类型 ClassA
,我从 item2 填充它。 A 类包含一个名为 LastItem4 的属性,比方说,它需要按照创建日期或其他顺序保留最后一个 item4。如果我使用计算来创建 instanceA
,那么这个计算只是部分的。因为 LastItem4 属性需要在不同的计算方法中在 item4 级别填充。那么我如何调用这两种计算方法来建议我实际在做什么呢?在我看来,这是一个艰难的答案。
<强>4。 #地区保留一个长方法但使用区域。这是一些编程语言中严格使用的功能,在我看来就像一个补丁,而不是最佳实践,但也许只有我一个人喜欢。
我想知道您将如何进行重构?请注意,它可能比这更复杂。这是一个服务的事实有点误导,这个想法是我真的不喜欢使用一次性对象作为方法参数,因为如果不阅读实际的方法代码你就不知道意图。但我在评论中期待这一点,因为其他人可能会有不同的看法。
为了举例,我们假设该服务是第 3 方服务,无法更改其工作方式。
最佳答案
您似乎在寻找一般答案而不是特定答案。一般答案的关键是分离职责并努力实现单一职责原则。
让我从您的方法做太多事情开始。理想情况下,一个类(class)也不应该做这么多事情。它应该在类组的帮助下完成。
Robert C.Martin 曾经说过“类往往隐藏在方法中”,这里就是这种情况。如果你的方法很大,你可以将它重构为更小的方法,但如果整个方法都需要一个局部变量,那么该方法可能应该放在它自己的类中。
如果您需要同时访问某些字段,则它们必须在一起(我的意思是在同一类型中)。所以你所有的 List1、List2、List3、List4 都应该放在一个类中,而不是作为方法参数。
鉴于您无法修改 Service
类(假设它是第三方 API)。没关系,您始终可以创建自己的类来包装上述服务。
所以你本质上是一个类似下面的类:
public class ServiceWrapper
{
private IList<string> list1;
private IList<string> list2;
private IList<string> list3;
private IList<string> list4;
private readonly Service1 service;
public ServiceWrapper(Service1 service)
{
this.service = service;
}
public SomeClass GetSomething()
{
list1 = service.Get1();
list2 = service.Get2();
foreach (var item2 in list2)
{
PopulateMore(item2);
}
return result;//Return some computed result
}
private void PopulateMore(string item2)
{
list3 = service.Get3(item2);
foreach (var item3 in list3)
{
PopulateEvenMore(item3);
}
}
private void PopulateEvenMore(string item3)
{
list4 = service.Get4(item3);
foreach (var item4 in list4)
{
//And so on
}
}
}
鉴于您的服务看起来像这样
public class Service1 : IDisposable
{
public void Dispose()
{
throw new NotImplementedException();
}
public IList<string> Get1()
{
throw new NotImplementedException();
}
public IList<string> Get2()
{
throw new NotImplementedException();
}
public IList<string> Get3(string item2)
{
throw new NotImplementedException();
}
public IList<string> Get4(string item3)
{
throw new NotImplementedException();
}
}
所以你很长的方法现在变得很小了。
public void YourVeryLongMethodBecomesVerySmall()
{
using (Service1 service = new Service1())
{
SomeClass result = new ServiceWrapper(service).GetSomething();
}
}
正如您在评论中所说,如果您在这些方法中还有一些其他职责,则需要将这些职责分开并将其移至自己的类中。例如,如果你想解析一些东西,那应该放在一些 Parser
类中,而 ServiceWrapper
应该使用解析器来完成工作(理想情况下有一些抽象和松耦合) .
你应该尽可能多地提取方法和类,这样提取就没有意义了。
关于java - 重构具有大量级别之间依赖关系的内部循环,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28476845/
这是代码片段。 请说出这种用小内存存储大数据的算法是什么。 public static void main(String[] args) { long longValue = 21474836
所以我使用 imap 从 gmail 和 outlook 接收电子邮件。 Gmail 像这样编码 =?UTF-8?B?UmU6IM69zq3OvyDOtc68zrHOuc67IG5ldyBlbWFpb
很久以前就学会了 C 代码;想用 Scheme 尝试一些新的和不同的东西。我正在尝试制作一个接受两个参数并返回两者中较大者的过程,例如 (define (larger x y) (if (> x
Azure 恢复服务保管库有两个备份配置选项 - LRS 与 GRS 这是一个有关 Azure 恢复服务保管库的问题。 当其驻留区域发生故障时,如何处理启用异地冗余的恢复服务保管库?如果未为恢复服务启
说,我有以下实体: @Entity public class A { @Id @GeneratedValue private Long id; @Embedded private
我有下一个问题。 我有下一个标准: criteria.add(Restrictions.in("entity.otherEntity", getOtherEntitiesList())); 如果我的
如果这是任何类型的重复,我会提前申请,但我找不到任何可以解决我的具体问题的内容。 这是我的程序: import java.util.Random; public class CarnivalGame{
我目前正在使用golang创建一个聚合管道,在其中使用“$ or”运算符查询文档。 结果是一堆需要分组的未分组文档,这样我就可以进入下一阶段,找到两个数据集之间的交集。 然后将其用于在单独的集合中进行
是否可以在正则表达式中创建 OR 条件。 我正在尝试查找包含此类模式的文件名列表的匹配项 第一个案例 xxxxx-hello.file 或者案例二 xxxx-hello-unasigned.file
该程序只是在用户输入行数时创建菱形的形状,因此它有 6 个 for 循环; 3 个循环创建第一个三角形,3 个循环创建另一个三角形,通过这 2 个三角形和 6 个循环,我们得到了一个菱形,这是整个程序
我有一个像这样的查询字符串 www.google.com?Department=Education & Finance&Department=Health 我有这些 li 标签,它们的查询字符串是这样
我有一个带有静态构造函数的类,我用它来读取 app.config 值。如何使用不同的配置值对类进行单元测试。我正在考虑在不同的应用程序域中运行每个测试,这样我就可以为每个测试执行静态构造函数 - 但我
我正在寻找一个可以容纳多个键的容器,如果我为其中一个键值输入保留值(例如 0),它会被视为“或”搜索。 map, int > myContainer; myContainer.insert(make_
我正在为 Web 应用程序创建数据库,并正在寻找一些建议来对可能具有多种类型的单个实体进行建模,每种类型具有不同的属性。 作为示例,假设我想为“数据源”对象创建一个关系模型。所有数据源都会有一些共享属
(1) =>CREATE TABLE T1(id BIGSERIAL PRIMARY KEY, name TEXT); CREATE TABLE (2) =>INSERT INTO T1 (name)
我不确定在使用别名时如何解决不明确的列引用。 假设有两个表,a 和 b,它们都有一个 name 列。如果我加入这两个表并为结果添加别名,我不知道如何为这两个表引用 name 列。我已经尝试了一些变体,
我的查询是: select * from table where id IN (1,5,4,3,2) 我想要的与这个顺序完全相同,不是从1...5,而是从1,5,4,3,2。我怎样才能做到这一点? 最
我正在使用 C# 代码执行动态生成的 MySQL 查询。抛出异常: CREATE TABLE dump ("@employee_OID" VARCHAR(50)); "{"You have an er
我有日期 2016-03-30T23:59:59.000000+0000。我可以知道它的格式是什么吗?因为如果我使用 yyyy-MM-dd'T'HH:mm:ss.SSS,它会抛出异常 最佳答案 Sim
我有一个示例模式,它的 SQL Fiddle 如下: http://sqlfiddle.com/#!2/6816b/2 这个 fiddle 只是根据 where 子句中的条件查询示例数据库,如下所示:
我是一名优秀的程序员,十分优秀!