阶梯模式实现
Stairway pattern implementation
我在 "Adaptive code via C#" 书中看到了 "Stairway" 模式描述,但我真的不明白这应该如何实现:
(source)
所以我有客户端组件:
using ServiceInterface;
namespace Client
{
class Program
{
static void Main(string[] args)
{
// Have to create service implementation somehow
// Where does ServiceFactory belong?
ServiceFactory serviceFactory = new ServiceFactory();
IService service = serviceFactory.CreateService();
service.Do();
}
}
}
服务接口组件:
namespace Service
{
public interface IService
{
void Do();
}
}
和服务实现组件:
using ServiceInterface;
namespace ServiceImplementation
{
public class PrintService : IService
{
public void Do()
{
Console.WriteLine("Some work done");
}
}
}
问题是:如何在 Client
命名空间中获取 IService
对象?我应该在哪里放置实际的 new PrintService()
对象创建?这不能是 ServiceInterface
的一部分,因为接口组件不依赖于 ServiceImplementation
。但它也不能是 Client
或 ServiceImplementation
的一部分,因为 Client
应该只依赖于 ServiceInterface
。
我找到的唯一解决方案是在它上面安装 Application
程序集,它引用了所有三个(Client
、ServiceInterface
和 ServiceImplementation
)和将 IService
注入 Client
。我错过了什么吗?
我会把它放在 ServiceFactory
中。您需要一些参数,例如传入工厂构造函数或从配置等中检索,确定工厂创建哪个 IService
实现。
在那种情况下,Client
项目应该包含对 Service
和 ServiceImplementation
的引用。这些引用将仅用于创建将用作 DI 的 IoC 容器。在应用程序启动时,您需要在 IoC 容器中注册所有接口实现。
如果您将针对 Service
接口实现 ServiceImplementation
,并且您将根据 Service
接口编写 Client
,那么将不会依赖于 ServiceImplementation
.
您还可以在 "Adaptive Code via C#":
的样本中看到阶梯模式是如何实现的
https://github.com/garymcleanhall/AdaptiveCode/tree/master/Sprints/sample-sprint2-markdown
根据 Mark Seemann 关于依赖注入的优秀书籍,应用程序入口点应该是组合根。在这里,问题更多地与依赖倒置有关,即客户端和实现都应该依赖于抽象。
该图没有显示,但希望本书的其他部分能说明的是,入口点自然且必然引用构建任何内容所需的一切是您的解析根(控制器、服务等),但这是 唯一 拥有此类知识的地方。
请记住,有时客户端 'own' 它们所依赖的接口是可以的:接口 ISecurityService
可能存在于 Controllers
程序集中,IUserRepository
可能存在于 ServiceImplementations
程序集中,等等。当然,当 >1 个客户端需要访问接口时,这是不切实际的。
如果你关注 SOLID,你自然会发现依赖注入是必要的,但控制反转容器的优先级较低。我发现自己越来越频繁地使用纯依赖注入(手动构建解析根)。
我在 "Adaptive code via C#" 书中看到了 "Stairway" 模式描述,但我真的不明白这应该如何实现:
所以我有客户端组件:
using ServiceInterface;
namespace Client
{
class Program
{
static void Main(string[] args)
{
// Have to create service implementation somehow
// Where does ServiceFactory belong?
ServiceFactory serviceFactory = new ServiceFactory();
IService service = serviceFactory.CreateService();
service.Do();
}
}
}
服务接口组件:
namespace Service
{
public interface IService
{
void Do();
}
}
和服务实现组件:
using ServiceInterface;
namespace ServiceImplementation
{
public class PrintService : IService
{
public void Do()
{
Console.WriteLine("Some work done");
}
}
}
问题是:如何在 Client
命名空间中获取 IService
对象?我应该在哪里放置实际的 new PrintService()
对象创建?这不能是 ServiceInterface
的一部分,因为接口组件不依赖于 ServiceImplementation
。但它也不能是 Client
或 ServiceImplementation
的一部分,因为 Client
应该只依赖于 ServiceInterface
。
我找到的唯一解决方案是在它上面安装 Application
程序集,它引用了所有三个(Client
、ServiceInterface
和 ServiceImplementation
)和将 IService
注入 Client
。我错过了什么吗?
我会把它放在 ServiceFactory
中。您需要一些参数,例如传入工厂构造函数或从配置等中检索,确定工厂创建哪个 IService
实现。
在那种情况下,Client
项目应该包含对 Service
和 ServiceImplementation
的引用。这些引用将仅用于创建将用作 DI 的 IoC 容器。在应用程序启动时,您需要在 IoC 容器中注册所有接口实现。
如果您将针对 Service
接口实现 ServiceImplementation
,并且您将根据 Service
接口编写 Client
,那么将不会依赖于 ServiceImplementation
.
您还可以在 "Adaptive Code via C#":
的样本中看到阶梯模式是如何实现的https://github.com/garymcleanhall/AdaptiveCode/tree/master/Sprints/sample-sprint2-markdown
根据 Mark Seemann 关于依赖注入的优秀书籍,应用程序入口点应该是组合根。在这里,问题更多地与依赖倒置有关,即客户端和实现都应该依赖于抽象。
该图没有显示,但希望本书的其他部分能说明的是,入口点自然且必然引用构建任何内容所需的一切是您的解析根(控制器、服务等),但这是 唯一 拥有此类知识的地方。
请记住,有时客户端 'own' 它们所依赖的接口是可以的:接口 ISecurityService
可能存在于 Controllers
程序集中,IUserRepository
可能存在于 ServiceImplementations
程序集中,等等。当然,当 >1 个客户端需要访问接口时,这是不切实际的。
如果你关注 SOLID,你自然会发现依赖注入是必要的,但控制反转容器的优先级较低。我发现自己越来越频繁地使用纯依赖注入(手动构建解析根)。