[ASP.NET Core 3 frame Disclosure] dependency injection: IoC mode

As we in the " dependency injection: inversion of control " mentioned, a lot of people will IoC understood as a kind of "object-oriented design patterns", in fact IoC not only with the object-oriented are not necessarily linked, it is not even their own It is a design pattern. In general, the design pattern provides a solution to some specific problem, but neither IoC a targeted problem areas, which itself does not provide a workable solution, so we are more inclined to IoC as a design principle. Behind many of us are familiar with design patterns have adopted the principle of IoC, then we have to introduce several typical "design mode."

A template method

IoC mentioned, many people first thought is dependency injection, but in my opinion was the most contact with the IoC closely touches another is called a " template method (Template Method,) " design pattern. The method of the template pattern can be said to coincide IoC intention that the claimed model a workflow will be multiplexed into a template method or algorithm defines a plurality of steps, the composition of the single step processes or algorithms are implemented in respective among the virtual method, template method to call these virtual method based on pre-programmed process. These methods are defined in a class, the derived class and we can rewrite the virtual method customized way to achieve the purpose of the process.

For example we have demonstrated this in front of MVC, we can request the entire process flow implemented in a MvcEngine class. The following code fragment, we monitor the reception of the request, performing activation and target Controller View, and presented are defined five protected virtual methods, the template has StartAsync method invocation request according to a predefined process flow these five methods.

public class MvcEngine
{
    public async Task StartAsync(Uri address)
    {
        await ListenAsync(address);
        while (true)
        {
            var request = await ReceiveAsync();
            var controller = await CreateControllerAsync(request);
            var view = await ExecuteControllerAsync(controller);
            await RenderViewAsync(view);
        }
    }
    protected virtual Task ListenAsync(Uri address);
    protected virtual Task<Request> ReceiveAsync();
    protected virtual Task<Controller> CreateControllerAsync(Request request);
    protected virtual Task<View> ExecuteControllerAsync(Controller controller);
    protected virtual Task RenderViewAsync(View view);
}

For specific applications, if defined in MvcEngine in handling requests for full compliance, it only needs to create a MvcEngine object, and then specify the address of a listener calls the template method StartAsync open the MVC engine can be. If one part of the MVC engine processes the request does not meet the requirements, we can create MvcEngine derived class and override the virtual method to achieve the appropriate link. For example, the definition of Controller in an application are stateless, it wants by way of Singleton (Singleton) has been activated Controller reuse objects to improve performance, then it can create a custom in the following manner FoobarMvcEngine and rewrite CreateControllerAsync method can in their own way.

public class FoobarMvcEngine : MvcEngine
{
    protected override Task<View> CreateControllerAsync (Request request)
    {
        << >> omitted achieve
    }
}

Second, the factory method

For a complex process, we tend to make up all aspects of the implementation process in the corresponding components, then it can be achieved by providing for the corresponding components in the form of customized processes. We know that among the 23 design patterns have an important type, that is, "to create a schema", such as the commonly used "factory method" and "abstract factory", shared with tailored processes IoC also be embodied by these designs mode to complete.

The so-called factory methods, saying that white is in a class defined method for providing the required services objects, this method can be a pure virtual method, it may be a default implementation of the virtual method. As the return type declaration may be an interface or abstract class, it can be unblocked (Sealed) the specific type. As its derived type, or rewrite the factory method can be implemented to provide the required service objects.

The same with our MVC framework, for example, we make several separate components to complete the core part of the entire request processing flow. Specifically, we define the following several interface corresponding to these core components. IWebListener interface is used to monitor, receive and respond to the request (returned by the method ReceiveAsync HttpContext context for the complete response to the request), IControllerActivator an interface for the current context activation target HttpContext Controller object, and do Controller object after the release of some recovery work performed according to . As IControllerExecutor and IViewRender were used to complete the implementation of the interfaces for the Controller and presentation for the View of.

public  interface IWebListener
{
    Task ListenAsync(Uri address);
    Task<HttpContext> ReceiveAsync();
}

public interface IControllerActivator
{
    Task<Controller> CreateControllerAsync(HttpContext httpContext);
    Task ReleaseAsync(Controller controller);
}

public interface IControllerExecutor
{
    Task<View> ExecuteAsync(Controller controller, HttpContext httpContext);
}

public  interface IViewRender
{
    Task RendAsync(View view, HttpContext httpContext);
}

We defined four factory methods (GetWebListener, GetControllerActivator, GetControllerExecutor and GetViewRenderer) in MvcEngine as MVC engine delivers these four components. The four factory methods are virtual methods have default implementations, we can use them to provide a default component. In StartAsync method for starting the engine, we use these objects to specific factory methods provided complete the requested processes.

public class MvcEngine
{
    public async Task StartAsync(Uri address)
    {
        was listener = GetWebListener ();
        was Activator = GetControllerActivator ();
        was executor = GetControllerExecutor ();
        was trenches = GetViewRender ();

        await listener.ListenAsync(address);
        while (true)
        {
            var httpContext = await listener.ReceiveAsync();
            var controller = await activator.CreateControllerAsync(httpContext);
            try
            {
                var view = await executor.ExecuteAsync(controller, httpContext);
                await render.RendAsync(view, httpContext);
            }
            finally
            {
                await activator.ReleaseAsync(controller);
            }
        }
    }
    protected virtual IWebLister GetWebListener(); 
    protected virtual IControllerActivator GetControllerActivator();
    protected virtual IControllerExecutor GetControllerExecutor();
    protected virtual IViewRender GetViewRender();
}

For specific applications, if one part needs to be customized request processing, it needs to be implemented in a custom implementation class corresponding to the operation of the interface. In MvcEngine derived class, we need to override factory method to provide the corresponding object can be customized. Controller object such as the goal of providing a single mode of the above-mentioned embodiment is defined in SingletonControllerActivator class, we derived a factory method to rewrite the FoobarMvcEngine MvcEngine GetControllerActivator class to return a SingletonControllerActivator object.

public class SingletonControllerActivator : IControllerActivator
{         
    public Task<Controller> CreateControllerAsync(HttpContext httpContext)
    {
        << >> omitted achieve
    }
    public Task ReleaseAsync(Controller controller) => Task.CompletedTask;
}

public class FoobarMvcEngine : MvcEngine
{
    protected override ControllerActivator GetControllerActivator() => new SingletonControllerActivator();
}

Third, the abstract factory

Although the factory method and abstract factory offers a "production" factory object instance, but there are different both in the design of nature. Factory method using a type defined in the abstract method for the complete or virtual methods " single object to provide", and the abstract factory using a separate interface is an abstract class, or to provide " a group of related objects ."

Specifically, we need to define a separate factory interface or abstract factory class and define multiple factory methods to provide " the same family " of a number of related objects. If the desired abstract factory with a default set of "output", we can not be a closed type as an abstract factory, factory method defined in the form of a virtual method of the default object as the return value. In a particular application development, we can achieve the factory interface or inherit the abstract factory class (not necessarily the abstract class) way to define concrete factory class and use it to provide a customized set of objects series.

Now we use the abstract factory pattern to transform our MVC framework. The following code fragment, we define an interface called as IMvcEngineFactory abstract factory, and which defines four methods for providing and processing request listening to use four core object. If for MVC provides a default implementation of the four core components, we can provide a default implementation (MvcEngineFactory) for the abstract factory in the following manner.

public interface IMvcEngineFactory
{
    IWebLister GetWebListener ();
    IControllerActivator GetControllerActivator();
    IControllerExecutor GetControllerExecutor();
    IViewRender GetViewRender ();
}

public class MvcEngineFactory: IMvcEngineFactory
{
    public virtual IWebLister GetWebListener();
    public virtual IControllerActivator GetControllerActivator();
    public virtual IControllerExecutor GetControllerExecutor();
    public virtual IViewRender GetViewRender();
}

Now we use the abstract factory pattern to transform our MVC framework. We offer a specific IMvcEngineFactory objects when creating MvcEngine object, if not explicitly specified, the default MvcEngine will use EngineFactory object. In StartAsync method for starting engines, MvcEngine using IMvcEngineFactory object to obtain the corresponding object to the request process flow.

public class MvcEngine
{
    public IMvcEngineFactory EngineFactory { get; }
    public MvcEngine(IMvcEngineFactory engineFactory = null)  => EngineFactory = engineFactory ?? new MvcEngineFactory();
        
    public async Task StartAsync(Uri address)
    {
        var listener = EngineFactory.GetWebListener();
        var activator = EngineFactory.GetControllerActivator();
        var executor = EngineFactory.GetControllerExecutor();
        var render = EngineFactory.GetViewRender();

        await listener.ListenAsync(address);
        while (true)
        {
            var httpContext = await listener.ReceiveAsync();
            var controller = await activator.CreateControllerAsync(httpContext);
            try
            {
                var view = await executor.ExecuteAsync(controller, httpContext);
                await render.RendAsync(view, httpContext);
            }
            finally
            {
                await activator.ReleaseAsync(controller);
            }
        }
    }        
}

If a particular application requires use of the previously defined single SingletonControllerActivator embodiment mode activated Controller to the target object may define a specific class FoobarEngineFactory factory according to the following manner. The final application will use this object to create a FoobarEngineFactory engine MvcEngine objects can be.

public class FoobarEngineFactory : EngineFactory
{
    public override ControllerActivator GetControllerActivator()
    {
        return new SingletonControllerActivator();
    }
}

public class App
{
    static async Task Main()
    {
        var address = new Uri("http://0.0.0.0:8080/mvcapp");
        var engine = new MvcEngine(new FoobarEngineFactory());
        await engine.StartAsync(address);
        ...
    }
}


[ASP.NET Core 3 frame Disclosure] dependency injection: Inversion of Control
[ASP.NET Core 3 frame Disclosure] dependency injection: the IoC mode
[ASP.NET Core 3 frame Disclosure] dependency injection: Dependency injection mode
[ASP.NET Core 3 framework Secret] dependency injection: a mini-version of the DI framework

Guess you like

Origin www.cnblogs.com/artech/p/inside-asp-net-core-03-02.html