gpt4 book ai didi

c# - 如何使用依赖注入(inject)完成可变对象重构?

转载 作者:行者123 更新时间:2023-11-30 15:23:30 25 4
gpt4 key购买 nike

存在一个“Audit”对象,它在我试图重构的整个代码库中使用,以允许依赖注入(inject),并最终实现更好的单元测试。到目前为止,我在为我的类创建接口(interface)并通过构造函数注入(inject)这些接口(interface)时没有遇到任何问题。然而,这个类是不同的。我知道为什么/如何不同,但我不确定如何修复它以“正常”工作。

这是一个示例(简化版本,但即使在示例中问题仍然存在):

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 函数(未显示实现)获取数据的“更改前”版本,删除数据(并审核它),插入/更新对数据的更改,然后审核插入/更新。

如果我要从控制台应用程序运行:

Console.WriteLine("\n");
test.DI.Original.MultiUseDependencies mud = new test.DI.Original.MultiUseDependencies();
mud.Update();

我会得到:

Audited Delete

Audited Update

这是预期的行为。现在在实现类的方式上,我已经可以看出会有问题,但我不确定如何纠正它。使用 DI 查看(初始)重构:

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();

我得到(如预期的那样,但不正确):

Audited Delete

Audited Delete

以上是基于实现的预期,但根据原始行为是不正确的。我不确定如何进行。原始实现依赖于不同的 Audit 来正确跟踪正在发生的变化。当我在重构中传递 IAudit 的实现时,我只得到一个 Audit 实例,其中两者相互碰撞。

基本上在重构之前,Audit 的范围在函数级别。重构后,Audit 的范围限定在类上。

有没有简单的方法来纠正这个问题?

这是一个实际的 fiddle : https://dotnetfiddle.net/YbpTm4

最佳答案

问题出在你的设计上。 Audit 是一个可变对象,使其成为运行时数据。注入(inject) runtime data into the constructors of your components is an anti-pattern .

解决方案是更改设计,例如定义一个 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");
}
}

但我什至应该更进一步,因为使用您当前的方法,您正在用横切关注点污染业务代码。审计跟踪的代码在整个代码库中分布和复制。

然而,这将对您的应用程序设计产生相当大的改变,但可能会非常有益。你绝对应该阅读 this article了解如何通过这种方式改进您的设计。

关于c# - 如何使用依赖注入(inject)完成可变对象重构?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34395654/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com