2

可能重复:
StructureMap 单例用法(实现两个接口的类)

我目前正在设计一个小型系统,并且我目前正在使用 structureMap 作为 IoC。我最近才明白接口隔离的意义……我现在想知道。

如果我有一个特定的业务对象,它将实现三个接口......我应该如何在代码的配置和实例化中处理这个?

假设我在一个简单的场景中有两个接口,用于一个名为 EmployeeServiceObject 的服务层类。IGenericEntity 和 IEmployeeServiceObject。

GenericEntity 将为类提供 CRUD 功能,而 IEmployeeServiceObject 将为业务查询/操作提供结果集。

如果在外观/服务层方法上,我必须使用 EmployeeServiceObject 类并实际使用两个接口的功能......应该如何处理?

最初我认为正确的做法是设置 IoC 的配置以将 IEmployeeServiceObject 映射到 EmployeeServiceObject,向工厂询问对象,然后在需要使用 CRUD 功能时将其转换为 IGenericEntity,但我不太确定. 这似乎也不正确,因为我永远不会正式声明具体类实际上正在实现未在 ioc 容器配置中设置的接口。

而且我绝对知道创建同一个具体类的两个实例但要求不同的接口......听起来更糟。

这应该如何处理?

4

3 回答 3

2

如果我正确理解了这个问题,那么您有以下场景(在 C# 代码中):

public interface IGenericEntity { /**/ }

public interface IEmployeeServiceObject { /**/ }

public class EmployeeServiceObject : IEmployeeServiceObject, IGenericEntity

如果是这样,那么 EmployeeServiceObject 实现这两个接口的事实就是一个实现细节。您可能有其他实现分别实现每个接口。

ISP 的重点是每个接口都建模一个单独的关注点,因此如果您经常发现自己处于需要 IGenericEntity 和 IEmployeeServiceObject 的情况,您应该质疑分离成两个接口是否有意义。

否则,您应该分别请求每个接口,因为任何强制转换的尝试都会违反Liskov Substitution Principle

在您确实需要两者的情况下,您需要同时请求两者:

public class Foo
{
    public Foo(IGenericEntity ge, IEmployeeServiceObject eso) { /**/ }

    // ...
}

如果您有一个类 (EployeeServiceObject) 实现了这两个接口,您需要告诉 DI 容器这是这种情况。在这一点上,我们正在进入特定于容器的细节领域,因此您如何做到这一点因每个容器而异。

例如,Windsor 具有 Forward 方法,可让您指定将一个接口的请求转发到另一种类型。

Poor Man's DI中它很简单

var eso = new EmployeeServiceObject();
var f = new Foo(eso, eso);

了解如何使用Poor Man's DI 构成依赖层次结构总是一件好事,因为它可以为您提供有价值的线索,让您了解容器如何理解同一事物。

于 2010-04-08T07:04:55.707 回答
0

如果可以的话,在解决 DI/IoC 实现之前,我想先介绍一下您的 API。我认为您的痛点正试图引导您进行更好的设计。

EmployeeServiceObject 似乎有太多的责任。在创建对象时考虑单一职责原则。在您的描述中, EmployeeServiceObject 既是外观/服务层是 CRUD 层。通过为 CRUD 操作(IGenericEntity)分配接口,您将 CRUD 实现公开给外观的使用者(IEmployeeServiceObject)。

鉴于您所描述的这种情况和类型,请考虑另一种方法(我还会重新考虑您的类型名称以更准确地描述它们的目的):

public interface IEmployeeServiceObject 
{
    // Service methods
    decimal GetSalary(string employeeId);
}

public class EmployeeServiceObject : IEmployeeServiceObject
{
    private IGenericEntity<Employee> _entity;

    public EmployeeServiceObject(IGenericEntity<Employee> entity)
    {
        _entity=entity;
    }

    public decimal GetSalary(string employeeId)
    {
        return _entity.Get(employeeId).Salary;
    }
}

public interface IGenericEntity<T>
{
    // CRUD Methods including...
    T Get(string id);
}

public class GenericEntity<T> : IGenericEntity<T> 
{
    T Get(string id){...}
}

使用您选择的容器注册 IEmployeeServiceObject/EmployeeServiceObject 和 IGenericEntity/GenericEntity 对。(StructureMap 可以按照约定注册这些类型。)

当您从容器请求 IEmployeeServiceObject 时,容器会先将 GenericEntity 注入到 EmployeeServiceObject 的构造函数中,然后再将其提供给您。

通过这种方式,您可以避免您描述的投射/注册问题。无需强制容器以次优方式工作。另外,您的外观只公开其客户所需的内容,并将 CRUD 操作推迟到另一个类(不需要向客户公开)。

于 2010-04-08T07:14:28.737 回答
0

我没有找到如何将我的问题关闭为重复...但我确切地找到了如何在另一个 stackoverflow 问题中做我需要的事情。

Mark 提到的 Windsor 中的 Forward 方法,它也存在于 StructureMap 中……看来这将是做事的正确方法。

StructureMap 单例用法(一个实现两个接口的类)

于 2010-04-08T17:12:34.400 回答