我有一个巨大的类A
,我想重构它并提取一个具有某些行为的分部类。现在我不想在一步中将A
重构为10个部分类,但我想首先采取第一个行为,将其重构为B
,然后在下次触及此类时采用连续重构方式另一种行为将其重构为C
。
然后A
作为一种main
将接受DI
方式B
和C
并将其用作帮助者。
我的问题是:
由于这是一个部分重构(连续......)B
而C
依赖于A
中的某些逻辑,因此无法将A
重构为B
{}}和C
没有B
和C
依赖于A
逻辑,否则我需要立即将A
分解为10或20个类。< / p>
我留下的是:
B
和C
以A
的方式接受(丑陋的)DI
,虽然丑陋但这会让我继续重构事件更糟A
是尚未准备好,直到我用帮助者B
和C
调用其构造函数时才构建。DI
也是不可接受的,它是一个混乱,我更喜欢ctor
中的依赖项。有关于此的任何想法吗?任何模式?
答案 0 :(得分:2)
通常这些是我用来重构的步骤/规则。按照这些步骤,我通常不会发现任何问题。示例在C#中。
删除静态函数(可选)
如果你想删除静态函数,通常我将它包装为一个类并进行默认字段注入(在C#
属性中)。请注意,这通常用于无状态功能。
public static class StaticExample{
public static void DoSomething(int a){ /*code here*/ }
}
public class WrapperExample{
public void DoSomething(int a){ return StaticExample.DoSomething(a); }
}
public class Consumer{
public WrapperExample wrapperExample = new WrapperExample();
public void ConsumeBefore(int a){ StaticExample.DoSomething(a); }
public void ConsumeAfter(int a){ wrapperExample.DoSomething(a); }
}
这对当前逻辑产生零影响,并为更多重构提供了良好的基线(依赖注入,修改Wrapper以不使用静态等等。
首先重构终点
通常一个函数执行几个步骤。一些例子是:
购物车结帐:获取购物车商品,验证购物车,验证付款,减去存储数量,将购物车标记为已完成,[打印发票]&lt; - 这是端点
回答stackoverflow问题:获取答案,验证答案,插入/标记答案为已发布,[发送通知]&lt; - 这是端点
这通常更容易完成,因为:
通常不需要太多数据操作,
通常它与外部依赖关系(如数据库或打印机)进行交互,因此值得提取。
第1点通常用重构类来解决循环依赖。
让它无国籍。如果它有状态,重构参数
说你的一个班级有这个:
public class Foo(
public string Bar = "";
public void DoSomething(){
// the code you want to refactor using Bar
}
)
成为
public class Foo(
public string Bar = "";
public RefactoredClass refactoredClass = new RefactoredClass();
public void DoSomething(){
refactoredClass.DoSomething(Bar);
}
)
几个类似的参数成为DTO
这个重构旨在简化太多参数。通常这意味着如果参数集彼此具有某种关系。例如(可能不是现实生活场景):
string cartId, string productId, int quantity --> CartItem
string cartId, string productId, int quantity, string userName, string invoiceNumber --> this is not right
第一个例子可以重构为DTO,因为参数仍然在同一个上下文中(CartItem
)。在第二个示例中,userName
和invoiceNumber
的上下文与productId
和quantity
无关。
它可能导致违反SRP
,因为看起来该函数将处理2个不同的事情。但是,如果将userName
和invoiceNumber
嵌入CartHeader
,其数组为CartItems
,则会成为一个上下文,可能会打印发票。
这是我的2美分。我没有任何来源或参考资料。
答案 1 :(得分:1)
因为你还没有真正说明你所说的那些依赖关系来自我正在做一些猜测。
你说在逐步重构之后,类B和C会有循环依赖关系回到A.听起来A中的逻辑是用一个大乱的方法写的,做了很多不同的事情,或者A的所有方法都是非常依赖于A的状态并不是很好(特别是如果你想进行单元测试)。这就是说我会建议尝试在有一个责任的方法中开始构造A的逻辑,或者(理想情况下)不依赖于状态(例如,你应该通过参数传递状态)。
因此,在不创建循环依赖关系的情况下将方法提取到辅助类中应该更容易。
答案 2 :(得分:1)
在官方重构提取类模式中找到了一个“官方”答案,该模式讨论了这个确切的问题:
http://sourcemaking.com/refactoring/extract-class
力学
06 决定如何分担班级的责任。 创建一个新类来表达分离责任。 如果旧类的职责不再与其名称匹配,则重命名旧类。 建立从旧班级到新班级的链接。 您可能需要双向链接。但是在你发现需要它之前不要制作反向链接。
所以有时候没有办法解决这个双向联系问题。
答案 3 :(得分:-1)
尝试Mediator模式。 A和部分类之间的所有交互都应该封装在mediator类中。