请选择 进入手机版 | 继续访问电脑版

马上加入IBC程序猿 各种源码随意下,各种教程随便看! 注册 每日签到 加入编程讨论群

C#教程 ASP.NET教程 C#视频教程程序源码享受不尽 C#技术求助 ASP.NET技术求助

【源码下载】 社群合作 申请版主 程序开发 【远程协助】 每天乐一乐 每日签到 【承接外包项目】 面试-葵花宝典下载

官方一群:

官方二群:

[ASP.NET Core 3框架揭秘] 依赖注入:IoC模式

[复制链接]
查看1974 | 回复1 | 2019-10-17 09:43:16 | 显示全部楼层 |阅读模式

正如我们在《依赖注入:控制反转》提到过的,很多人将IoC明确为一种“面向对象的设计模式”,实际上IoC不仅与面向对象没有肯定的联系,它自身以致算不上是一种设计模式。一般来讲,设计模式提供了一种办理某种具体题目标方案,但是IoC既没有一个针对性的题目范畴,其自身也没有提供一种可操作性的办理方案,所以我们更加倾向于将IoC视为一种设计原则。很多我们认识的设计模式背后都采取了IoC原则,接下来我们就来先容几种典型的“设计模式”。

一、模板方法

提到IoC,很多人起首想到的是依赖注入,但是在我看来与IoC联系得最为紧密的倒是另一种被称为“模板方法(Template Method)”的设计模式。模板方法模式与IoC的意图可以说不谋而合,该模式主张将一个可复用的工作流程大概由多个步骤构成的算法定义成模板方法,构成这个流程大概算法的单一步骤则实现在相应的虚方法之中,模板方法根据预先编排的流程去调用这些虚方法。这些方法均定义在一个类中,我们可以通过派生该类并重写相应的虚方法的方式到达对流程定制的目标。

对于前面我们演示的这个MVC的例子,我们可以将整个请求处理流程实现在一个MvcEngine类中。如下面的代码片段所示,我们将请求的监听与接收、目标Controller的激活与执行以及View的呈现分别定义在5个受掩护的虚方法中,模板方法StartAsync根据预定义的请求处理流程先后调用这5个方法。

  1. public class MvcEngine
  2. {
  3. public async Task StartAsync(Uri address)
  4. {
  5. await ListenAsync(address);
  6. while (true)
  7. {
  8. var request = await ReceiveAsync();
  9. var controller = await CreateControllerAsync(request);
  10. var view = await ExecuteControllerAsync(controller);
  11. await RenderViewAsync(view);
  12. }
  13. }
  14. protected virtual Task ListenAsync(Uri address);
  15. protected virtual Task<Request> ReceiveAsync();
  16. protected virtual Task<Controller> CreateControllerAsync(Request request);
  17. protected virtual Task<View> ExecuteControllerAsync(Controller controller);
  18. protected virtual Task RenderViewAsync(View view);
  19. }
复制代码

对于具体的应用步伐来说,假如定义在MvcEngine中针对请求的处理方式完全符合要求,它只需要创建一个MvcEngine对象,然后指定一个监听地点调用模板方法StartAsync开启这个MVC引擎即可。假如该MVC引擎处理请求的某个环节不能满意要求,我们可以创建MvcEngine的派生类,并重写实现该环节的相应虚方法即可。比如说定义在某个应用步伐中的Controller都是无状态的,它希望采取单例(Singleton)的方式重用已经激活的Controller对象以进步性能,那么它就可以按照如下的方式创建一个自定义的FoobarMvcEngine并按照本身的方式重写CreateControllerAsync方法即可。

  1. public class FoobarMvcEngine : MvcEngine
  2. {
  3. protected override Task<View> CreateControllerAsync (Request request)
  4. {
  5. <<省略实现>>
  6. }
  7. }
复制代码

二、工厂方法

对于一个复杂的流程来说,我们倾向于将构成该流程的各个环节实现在相应的组件之中,那么针对流程的定制就可以通过提供相应组件的情势来实现。我们知道23种设计模式之中有一种告急的类型,那就是“创建型模式”,比如常用的“工厂方法”和“抽象工厂”,IoC所体现的针对流程的共享与定制同样可以通过这些设计模式来完成。

所谓的工厂方法,说白了就是在某个类中定义用来提供所需服务对象的方法,这个方法可以是一个单纯的虚方法,也可以是具有默认实现的虚方法。至于方法声明的返回类型,可以是一个接口大概抽象类,也可以是未封闭(Sealed)的具体类型。作为它的派生类型,可以实现大概重写工厂方法以提供所需的服务对象。

同样以我们的MVC框架为例,我们让独立的组件来完成整个请求处理流程的几个核心环节。具体来说,我们为这些核心组件定义了如下几个对应的接口。IWebListener接口用来监听、接收和相应请求(针对请求的相应由ReceiveAsync方法返回的HttpContext上下文来完成),IControllerActivator接口用于根据当前HttpContext上下文激活目标Controller对象,并在Controller对象执行后做一些开释接纳工作。至于IControllerExecutor和IViewRender接口则分别用来完成针对Controller的执行和针对View的呈现。

  1. public interface IWebListener
  2. {
  3. Task ListenAsync(Uri address);
  4. Task<HttpContext> ReceiveAsync();
  5. }
  6. public interface IControllerActivator
  7. {
  8. Task<Controller> CreateControllerAsync(HttpContext httpContext);
  9. Task ReleaseAsync(Controller controller);
  10. }
  11. public interface IControllerExecutor
  12. {
  13. Task<View> ExecuteAsync(Controller controller, HttpContext httpContext);
  14. }
  15. public interface IViewRender
  16. {
  17. Task RendAsync(View view, HttpContext httpContext);
  18. }
复制代码

我们在作为MVC引擎的MvcEngine中定义了四个工厂方法(GetWebListener、GetControllerActivator、GetControllerExecutor和GetViewRenderer)来提供上述这四种组件。这四个工厂方法均为具有默认实现的虚方法,我们可以使用它们提供默认的组件。在用于启动引擎的StartAsync方法中,我们使用这些工厂方法提供的对象来具体完成整个请求处理流程。

  1. public class MvcEngine
  2. {
  3. public async Task StartAsync(Uri address)
  4. {
  5. var listener = GetWebListener();
  6. var activator = GetControllerActivator();
  7. var executor = GetControllerExecutor();
  8. var render = GetViewRender();
  9. await listener.ListenAsync(address);
  10. while (true)
  11. {
  12. var httpContext = await listener.ReceiveAsync();
  13. var controller = await activator.CreateControllerAsync(httpContext);
  14. try
  15. {
  16. var view = await executor.ExecuteAsync(controller, httpContext);
  17. await render.RendAsync(view, httpContext);
  18. }
  19. finally
  20. {
  21. await activator.ReleaseAsync(controller);
  22. }
  23. }
  24. }
  25. protected virtual IWebLister GetWebListener();
  26. protected virtual IControllerActivator GetControllerActivator();
  27. protected virtual IControllerExecutor GetControllerExecutor();
  28. protected virtual IViewRender GetViewRender();
  29. }
复制代码

对于具体的应用步伐来说,假如需要对请求处理的某个环节进行定制,它需要将定制的操作实现在对应接口的实现类中。在MvcEngine的派生类中,我们需要重写对应的工厂方法来提供被定制的对象即可。 比如上面提及的以单例模式提供目标Controller对象的实现就定义在SingletonControllerActivator类中,我们在派生于MvcEngine的FoobarMvcEngine类中重写了工厂方法GetControllerActivator使其返回一个SingletonControllerActivator对象。

  1. public class SingletonControllerActivator : IControllerActivator
  2. {
  3. public Task<Controller> CreateControllerAsync(HttpContext httpContext)
  4. {
  5. <<省略实现>>
  6. }
  7. public Task ReleaseAsync(Controller controller) => Task.CompletedTask;
  8. }
  9. public class FoobarMvcEngine : MvcEngine
  10. {
  11. protected override ControllerActivator GetControllerActivator() => new SingletonControllerActivator();
  12. }
复制代码

三、抽象工厂

虽然工厂方法和抽象工厂均提供了一个“生产”对象实例的工厂,但是两者在设计上却有本质的不同。工厂方法使用定义在某个类型的抽象方法大概虚方法完成了针对“单一对象”的提供,而抽象工厂则使用一个独立的接口大概抽象类来提供“一组相干的对象”。

具体来说,我们需要定义一个独立的工厂接口大概抽象工厂类,并在其中定义多个工厂方法来提供“同一系列”的多个相干对象。假如希望抽象工厂具有一组默认的“产出”,我们也可以将一个未被封闭类型作为抽象工厂,以虚方法情势定义的工厂方法将默认的对象作为返回值。在具体的应用开辟中,我们可以通过实现工厂接口大概继承抽象工厂类(不肯定是抽象类)的方式来定义具体工厂类,并使用它来提供一组定制的对象系列。

现在我们采取抽象工厂模式来改造我们的MVC框架。如下面的代码片段所示,我们定义了一个名为IMvcEngineFactory的接口作为抽象工厂,并在其中定义了四个方法来提供请求监听和处理过程使用到的四种核心对象。假如MVC提供了针对这四种核心组件的默认实现,我们可以按照如下的方式为这个抽象工厂提供一个默认实现(MvcEngineFactory)。

  1. public interface IMvcEngineFactory
  2. {
  3. IWebLister GetWebListener();
  4. IControllerActivator GetControllerActivator();
  5. IControllerExecutor GetControllerExecutor();
  6. IViewRender GetViewRender();
  7. }
  8. public class MvcEngineFactory: IMvcEngineFactory
  9. {
  10. public virtual IWebLister GetWebListener();
  11. public virtual IControllerActivator GetControllerActivator();
  12. public virtual IControllerExecutor GetControllerExecutor();
  13. public virtual IViewRender GetViewRender();
  14. }
复制代码

现在我们采取抽象工厂模式来改造我们的MVC框架。我们在创建MvcEngine对象的时候提供一个具体的IMvcEngineFactory对象,假如没有显式指定,MvcEngine会默认使用EngineFactory对象。在用于启动引擎的StartAsync方法中,MvcEngine使用IMvcEngineFactory对象来获取相应的对象来完成对请求的处理流程。

  1. public class MvcEngine
  2. {
  3. public IMvcEngineFactory EngineFactory { get; }
  4. public MvcEngine(IMvcEngineFactory engineFactory = null) => EngineFactory = engineFactory ?? new MvcEngineFactory();
  5. public async Task StartAsync(Uri address)
  6. {
  7. var listener = EngineFactory.GetWebListener();
  8. var activator = EngineFactory.GetControllerActivator();
  9. var executor = EngineFactory.GetControllerExecutor();
  10. var render = EngineFactory.GetViewRender();
  11. await listener.ListenAsync(address);
  12. while (true)
  13. {
  14. var httpContext = await listener.ReceiveAsync();
  15. var controller = await activator.CreateControllerAsync(httpContext);
  16. try
  17. {
  18. var view = await executor.ExecuteAsync(controller, httpContext);
  19. await render.RendAsync(view, httpContext);
  20. }
  21. finally
  22. {
  23. await activator.ReleaseAsync(controller);
  24. }
  25. }
  26. }
  27. }
复制代码

假如具体的应用步伐需要采取前面定义的SingletonControllerActivator以单例的模式来激活目标Controller对对象,可以按照如下的方式定义一个具体的工厂类FoobarEngineFactory。最终的应用步伐将使用这个FoobarEngineFactory对象来创建作为引擎的MvcEngine对象即可。

  1. public class FoobarEngineFactory : EngineFactory
  2. {
  3. public override ControllerActivator GetControllerActivator()
  4. {
  5. return new SingletonControllerActivator();
  6. }
  7. }
  8. public class App
  9. {
  10. static async Task Main()
  11. {
  12. var address = new Uri("http://0.0.0.0:8080/mvcapp");
  13. var engine = new MvcEngine(new FoobarEngineFactory());
  14. await engine.StartAsync(address);
  15. ...
  16. }
  17. }
复制代码


[ASP.NET Core 3框架揭秘] 依赖注入:控制反转
[ASP.NET Core 3框架揭秘] 依赖注入:IoC模式
[ASP.NET Core 3框架揭秘] 依赖注入:依赖注入模式
[ASP.NET Core 3框架揭秘] 依赖注入:一个迷你版DI框架







来源:https://www.cnblogs.com/artech/p/inside-asp-net-core-03-02.html
C#论坛 www.ibcibc.com IBC编程社区
C#
C#论坛
IBC编程社区
*滑块验证:
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则