如何使用依赖项注入实现可变对象重构
本文关键字:对象 重构 实现 注入 何使用 依赖 | 更新日期: 2023-09-27 18:27:45
存在一个"审计;对象,该对象在我试图重构的整个代码库中使用,以允许依赖项注入,并最终进行更好的单元测试。到目前为止,我为类创建接口并通过构造函数注入这些接口没有遇到任何问题。然而,这一类是不同的。我知道它为什么/如何不同,但我不确定如何将其修复为工作";适当地";。
下面是一个例子(简化版本,但问题仍然存在,即使在这个例子中也是如此):
namespace ConsoleApplication1.test.DI.Original
{
public class MultiUseDependencies
{
public MultiUseDependencies()
{
}
public void Update()
{
Audit a = new Audit();
a.preAuditValues = "Update";
// if data already exists, delete it
this.Delete();
// Update values, implementation not important
// Audit changes to the data
a.AuditInformation();
}
public void Delete()
{
Audit a = new Audit();
a.preAuditValues = "Delete";
// Delete data, implementation omitted.
a.AuditInformation();
}
}
public class Audit
{
public string preAuditValues { get; set; }
public void AuditInformation()
{
Console.WriteLine("Audited {0}", preAuditValues);
}
}
}
在上文中,Update
函数(实现方式未示出)获得"0";改变前";版本的数据,删除数据(并审核它),插入/更新对数据的更改,然后审核插入/更新。
如果我要从控制台应用程序运行:
Console.WriteLine("'n");
test.DI.Original.MultiUseDependencies mud = new test.DI.Original.MultiUseDependencies();
mud.Update();
我会得到:
已审核删除
经审核的更新
这是预期的行为。现在,在类的实现方式中,我已经可以看到会有问题,但我不确定如何纠正它
namespace ConsoleApplication1.test.DI.Refactored
{
public class MultiUseDependencies
{
private readonly IAudit _audit;
public MultiUseDependencies(IAudit audit)
{
_audit = audit;
}
public void Update()
{
_audit.preAuditValues = "Update";
// if data already exists, delete it
this.Delete();
// Update values, implementation not important
// Audit changes to the data
_audit.AuditInformation();
}
public void Delete()
{
_audit.preAuditValues = "Delete";
// Delete data, implementation omitted.
_audit.AuditInformation();
}
}
public interface IAudit
{
string preAuditValues { get; set; }
void AuditInformation();
}
public class Audit : IAudit
{
public string preAuditValues { get; set; }
public void AuditInformation()
{
Console.WriteLine("Audited {0}", preAuditValues);
}
}
}
运行:
Console.WriteLine("'n");
test.DI.Refactored.MultiUseDependencies mudRefactored = new test.DI.Refactored.MultiUseDependencies(new test.DI.Refactored.Audit());
mudRefactored.Update();
我得到(如预期,但不正确):
已审核删除
已审核删除
以上内容是基于实现的预期内容,但根据原始行为是不正确的。我不知道该怎么办。最初的实现依赖于不同的Audit
来正确地跟踪变化。当我在重构中传递IAudit
的实现时,我只得到Audit
的一个实例,其中两个实例相互碰撞。
基本上在重构之前,Audit
的作用域在函数级别。重构之后,Audit
的作用域在类上。
有没有一种简单的方法来纠正这个问题?
这是一把小提琴:https://dotnetfiddle.net/YbpTm4
问题出在您的设计中。Audit
是一个可更改的对象,它使它成为运行时数据。将运行时数据注入组件的构造函数是一种反模式。
解决方案是更改设计,例如,通过定义如下IAudit
抽象:
public interface IAuditHandler {
void AuditInformation(string preAuditValues);
}
对于这个抽象,您可以创建以下实现:
public class AuditHandler : IAuditHandler {
public void AuditInformation(string preAuditValues) {
var audit = new Audit();
audit.preAuditValues = preAuditValues;
audit.AuditInformation();
}
}
消费者现在可以依赖IAuditHandler
:
public class MultiUseDependencies
{
private readonly IAuditHandler _auditHandler;
public MultiUseDependencies(IAuditHandler auditHandler) {
_auditHandler = auditHandler;
}
public void Update() {
this.Delete();
_auditHandler.AuditInformation("Update");
}
public void Delete() {
// Delete data, implementation omitted.
_auditHandler.AuditInformation("Delete");
}
}
但我甚至应该更进一步,因为用您当前的方法,您正在用交叉的问题污染业务代码。审计跟踪的代码分布在整个代码库中并重复。
然而,这将是应用程序设计中的一个相当大的变化,但可能非常有益。你绝对应该阅读这篇文章,了解如何通过这种方式改进你的设计。
试试这个:
public void Update()
{
// if data already exists, delete it
this.Delete();
//preAuditValues should be changed after the delete or it will keep
//the old value
_audit.preAuditValues = "Update";
// Update values, implementation not important
// Audit changes to the data
_audit.AuditInformation();
}
或者这也应该起作用:
public void Delete()
{
string oldValue = _audit.preAuditValues;
_audit.preAuditValues = "Delete";
// Delete data, implementation omitted.
_audit.AuditInformation();
//Restoring oldValue after finished with Delete
_audit.preAuditValues = oldValue ;
}