Design patterns 使用IoC容器时如何管理接口隔离?

Design patterns 使用IoC容器时如何管理接口隔离?,design-patterns,inversion-of-control,structuremap,ioc-container,design-principles,Design Patterns,Inversion Of Control,Structuremap,Ioc Container,Design Principles,可能重复: 我目前正在设计一个小系统,我目前正在使用structureMap作为IoC。我最近才意识到界面隔离的重要性…现在我想知道 如果我有一个特定的业务对象,它将实现三个接口。。。我应该如何在代码的配置和安装中处理这个问题 假设我在一个简单的场景中有两个接口,用于名为EmployeeServiceObject的服务层类。iGenericeEntity和IEmployeeServiceObject GenericEntity将为类提供CRUD功能,而IEEmployeeServiceObje

可能重复:

我目前正在设计一个小系统,我目前正在使用structureMap作为IoC。我最近才意识到界面隔离的重要性…现在我想知道

如果我有一个特定的业务对象,它将实现三个接口。。。我应该如何在代码的配置和安装中处理这个问题

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

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

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

起初,我认为正确的做法是设置IoC的配置,将IEmployeeServiceObject映射到EmployeeServiceObject,向工厂请求对象,并在需要使用CRUD功能时将其转换为iGenericeEntity,但我不太确定。它似乎也不正确,因为我从来没有正式声明过具体类实际上正在实现未在ioc容器配置中设置的接口

我当然知道,创建同一个具体类的两个实例,但要求不同的接口……听起来更糟


如何处理这个问题?

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

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

ISP的要点是,每个接口都有一个单独的关注点,因此,如果您经常发现自己处于同时需要IGenericEntity和IEEmployeeServiceObject的情况下,您应该质疑将其分为两个接口是否有意义

否则,您应该分别请求每个接口,因为任何强制转换的尝试都会破坏接口

如果您确实需要两者,则需要同时请求:

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

    // ...
}
如果有一个类(EployeeServiceObject)实现两个接口,则需要告诉DI容器情况就是这样。现在,我们将进入特定于容器的详细信息区域,因此您如何做到这一点会因每个容器而异

例如,Windsor的Forward方法允许您指定将一个接口的请求转发到另一种类型

在穷人的DI中,它就像

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

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

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

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

给出了您所描述的这种情况和类型,请考虑不同的方法(我也会重新考虑您的类型名称来更准确地描述它们的目的):

公共接口IEmployeeServiceObject
{
//服务方式
十进制GetSalary(字符串employeeId);
}
公共类EmployeeServiceObject:IEEmployeeServiceObject
{
私人IGenericEntity(实体);
公共EmployeeServiceObject(IGenericEntity实体)
{
_实体=实体;
}
公共十进制GetSalary(字符串employeeId)
{
return _entity.Get(employeeId).Salary;
}
}
公共接口智能实体
{
//积垢方法包括。。。
T Get(字符串id);
}
公共类通用实体:IGenericEntity
{
无法获取(字符串id){…}
}
在所选容器中注册IEEmployeeServiceObject/EmployeeServiceObject和IGenericEntity/GenericEntity对。(StructureMap可以按约定注册这些类型。)

当您从容器请求IEEmployeeServiceObject时,容器将在将GenericEntity提供给您之前将其注入EmployeeServiceObject的构造函数中


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

我没有找到如何以重复的形式结束我的问题……但我在另一个stackoverflow问题中找到了正确的方法

马克在温莎提到的正向方法,也存在于StructureMap中……看来这是正确的方法


您好,我不知道如何在StructureMap中执行此操作的详细信息,但您应该能够注册具有多个接口的类。然后,您可以设置singleton作用域,以便在请求任一接口时检索相同的实例。谢谢Sam。我不想知道如何在StructureMap上执行此操作。。我正在寻找处理任何国际奥委会容器的方法……如何处理的原则。马克。谢谢你提出了不同的方法。实际上,你说得对,设计不是最优化的,CRUD功能不应该在服务层中公开,然而,这只是我提出的一个场景,与我的类似。就像你的设计一样
var eso = new EmployeeServiceObject();
var f = new Foo(eso, eso);
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){...}
}