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