解决模块化架构中的前向引用

时间:2015-12-08 09:06:22

标签: c# architecture module

在我的(C#)软件项目中,我有几个模块(由不同的Visual Studio项目表示) - 由于历史原因 - 有很多循环依赖(紧耦合)。

我目前正在尝试解决/删除循环引用。我已经添加了依赖注入 - 当然,这并不能解决/删除循环引用。

所以,我正在考虑使用事件来解决"转发"依赖。他们不会直接调用前向依赖,而是会在此事件上注册。

但是,其中一些依赖项需要在其他依赖项之前执行,例如这样(dumbed down)示例:

void DeleteCompany(int companyId)
{
    // must run before other dependencies
    ForwardDepend1.OnCompanyDeleted(companyId);

    // can run in parallel
    ForwardDepend2.OnCompanyDeleted(companyId);
    ForwardDepend3.OnCompanyDeleted(companyId);

    // must run as last command
    this.OnCompanyDeleted(companyId);
}

ForwardDependX的所有类都取决于当前的类;所以这些是我想要解决的循环引用。

是否有任何现有的模式可以解决这种复杂的事件"机制?或者是否有其他更好的方法可以解决这个问题?

我尝试使用谷歌搜索这个问题,但我找不到任何好的搜索关键字。

2 个答案:

答案 0 :(得分:0)

我认为使用事件来改善紧密耦合设计并不是最好的选择,因为它们往往会使依赖性变得不那么明显。并且您确实需要明确所有依赖项来处理循环引用。

我建议您逐步应用dependency inversion principleinterface segregation principle。通过构造函数将新引入的接口传递给客户端,并使用DI来组合它们。

此外,依赖可视化工具确实有助于这些情况。我过去曾使用Resharper和NDepend来完成这些任务,两者都运行良好。

DIP的例子

这是一个示例,说明如何使用DIP解决循环依赖关系。所以假设你有两个相互依赖的类:

class A 
{
  private readonly B _b;

  public A(B b) {
      _b = b;
  }

  public void DoIt() {
    // ...
  }
}

class B 
{
  public void DoSomething(A a) {
    a.DoIt();
  }
}

这意味着我们有一个像这样的依赖图:

A <--> B

现在在类中引入一个构成较弱依赖关系的接口,在本例中为A(因为A仅在B暂时使用)。

interface IA 
{
  void DoIt();
}

class A : IA
{
  private readonly B _b;

  public A(B b) {
      _b = b;
  }

  public void DoIt() {
    // ...
  }
}

class B 
{
  public void DoSomething(IA a) {
    a.DoIt();
  }
}

随着界面的引入,依赖关系圈已被破坏:

 A ----
 |     |
 v     v
IA <-- B 

答案 1 :(得分:0)

那不会解决你的问题。相反,你应该创建多个事件并将它们连接起来。

你说你有依赖关系1-3必须在CompanyDeleted事件上按顺序运行,并且你自己的事件处理程序应该最后运行。

这是一种脆弱的方法。我们假设依赖项的名称如下:

  • 给messageManager
  • ProjectManager
  • 的UserManager

动机是消息管理器必须首先运行,以便它可以从用户管理器中找到所有用户,并从项目管理器中找到所有项目,以便能够删除它的消息。

您可以改为反转该过程。聆听事件UserDeleted以删除用户的所有消息,并删除ProjectDeleted甚至删除项目的所有消息。

所以现在你在CompanyManager的事件处理程序之间没有时间耦合,因为你只有一个事件处理程序。

它当然意味着更多的工作,因为你必须识别新事件并创建它们。好处是您可以在IoC容器的帮助下解决事件订阅。

创建一个名为IEventHandler<T>的新界面:

public interface IEventHandler<T>
{
    void Handle(T evt);
}

让你的类实现它:

public class UserManager : IEventHandler<CustomerDeleted>
{
    public UserManager(IUserRepository repos, IEventPublisher publisher)
    {
    }

    public void Handle(CustomerDeleted evt)
    {
        var users = _repos.FindUsersForCustomer(evt.CustomerId);
        foreach (var user in users)
        {
            _repos.Delete(user);
            _publisher.Publish(new UserDeleted(user.Id, user.CustomerId));
        }
    }
}

事件发布者本身使用您的容器(用于服务位置)。实施因容器而异:

public class EventPublisher : IEventPublisher
{
    public EventPublisher(IYourContainerInterface container)
    {
    }

    public void Publish<TEvent>(TEvent evt)
    {
        var handlers = _container.ResolveAll<TEvent>();
        foreach (var handler in handlers)
        {
            handler.Publish(evt);
        }
    }
}

希望有所帮助。