楼梯模式实施
我在“自适应代码通过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
。 我错过了什么吗?
应用入口点应该是组合根,根据Mark Seemann关于dependency injection的优秀书籍。 在这里,问题更多的是关于依赖性倒置,客户端和实现都应该依赖于抽象。
这个图表没有显示,但希望本书的其他部分明确指出,入口点自然而且必然会引用构建你的解析根源(控制器,服务等)所需的一切 。但这是唯一拥有这种知识的地方。
请记住,客户端有时可以“拥有”它们所依赖的接口:接口ISecurityService
可能存在于Controllers
程序IUserRepository
, IUserRepository
可能存在于ServiceImplementations
程序集中,依此类推。 当然,当> 1客户端需要访问接口时,这是不切实际的。
如果您遵循SOLID,您自然会发现dependency injection是必需的,但控制反转容器不是优先考虑的事情。 我发现自己越来越多地使用Pure Dependency Injection(手动构建解析根)。
在这种情况下, Client
项目应包含对Service
和ServiceImplementation
引用。 这些引用仅用于创建将用作DI的IoC容器。 在应用程序启动时,您需要在IoC容器中注册所有接口实现。
如果您将针对Service
接口实现ServiceImplementation
,并且您将基于Service
intereface对Client
进行编码,那么将不依赖于ServiceImplementation
。
您还可以在“自适应代码通过C#”的示例中看到如何实现Stairway模式:
https://github.com/garymcleanhall/AdaptiveCode/tree/master/Sprints/sample-sprint2-markdown
我会把它放在ServiceFactory
。 您需要一些参数,例如在工厂构造函数中传递或从配置等中检索,这些参数确定工厂创建的IService
实现。