Do not call me, I'll call you (Inversion of Control principles)

Foreword

Seen before senior Artech "https://www.cnblogs.com/artech/" on Inversion of Control of an article, the article easy to understand and refined speech, writing blog is to share not only the accumulation, since it is then necessary to allow readers to share be able to understand what in the end to explain, so here I am also under challenge yourself to see if the concept can not be fully explained by the form of the code simple and clear language, if wrong, but also look correction.

What is Inversion of Control

Inversion of Control English called Inversion Of Control, we referred to as IOC, inversion of control is a principle rather than a design pattern, it is the reverse flow control program, the term Steapano Mazzocchi of the Apache Software Foundation project in Avalon It was extended, and then further popularized by Robert C. Martin and Martin Fowler in 2004. As Martin Fowler said: Inversion of control is a common feature of the frame, and therefore say that these lightweight containers reason in particular because they use inversion of control, as if to say my car is special because it is the same with wheels. It is essentially define the characteristics of the frame, a modular inversion control program and make increased scalability. So the question is, where is it truly reflects the reversal? In early computer software, the general procedure for the command line, the user interface is controlled by the application itself, in the process, we can be in response to an input command to directly control flow of the program, but in the GUI program, we basically the transfer of control to the windowing system (UI framework), and then decide what to do next window system, the main control program at this time we moved from UI framework. Inversion control is the difference between the libraries and frameworks, using the library, the library is essentially a method calls to specific functions and to perform calculations and operations, some of the work will be completed each call, and returns control to the client, and framework will be completed some of the work for us, we only need to register the code we have written in different positions of the frame, then the framework will call our code when needed. Understanding with a more user-friendly if it is: do not call me, I'll call you or do not call us, we will inform you (Hollywood law). Have a preliminary understanding of the concept, then we have to deepen the understanding of the concept in the form of code.

    /// <summary>
    /// 车引擎类
    /// </summary>
    public class Engine { }

    /// <summary>
    /// 汽车类
    /// </summary>
    public class Car
    {
        private Engine engine;

        public Car()
        {
            engine = new Engine();
        }
    }

We hand, the above code, because the composition is inseparable from the car's engine configuration, when we call the car object instance, will take the initiative to construct the object instance engine without any problems on the statements, but we realized in close connection with the engine and the car together, If the engine configuration object change event, there is no doubt that we need to modify the car object, that object is strongly dependent on the car engine objects, now we will modify the code as follows:

    /// <summary>
    /// 汽车类
    /// </summary>
    public class Car
    {
        private Engine _engine;

        public Car( Engine engine)
        {
            _engine = engine;
        }
    }

In this case, the object does not know how to construct a car engine object when calling the car, the car of the caller will have the responsibility and obligation to object to the instance of the engine car, this time process control is reversed, this reversal similar event-based processing mechanism. That process management transferred from the application to the frame, after such a modification, engine rose to a framework, such as the black box in general, because we do not care how specific engine configuration. We can also see, by inversion of control make the program more flexible and loosely coupled. Finished concepts and examples of Inversion of Control, we seem to have a not explain, it seems we hear more of Dependency Injection, dependency injection and inversion of control that has a kind of link? Inversion of Control and the Dependency injection two related but distinct concepts, ideas dependency injection is a single object, that white is prepared based manner, such that a particular instance of the class or function can be configured passed to them when, in fact, dependency injection it means inversion of control, because when we call a method on the object, they are no longer locate other objects they need. Instead, they had been given at the time of construction of the dependencies, but we still have to manage construction, by inverting the container using the controls, we can make further dependency injection by inversion of control container, we only need to pre-register All available classes. When the need to construct the container instance of a class, it can check which objects of that class constructor requires, then the class is registered Examples of suitable configuration, dependency injection in general is to achieve a method of controlling the inversion only way. We put aside the dependency injection to achieve the inversion of control, dependency injection only discuss only what has brought benefits.

 

Since it is an object-oriented language, then we are writing object-oriented code-based, so there is naturally an object of its life cycle, we need some objects may be only one instance, there has been some objects may run the entire program is in the process of global instance, and there are some references to objects inside other objects, this way will cause any problems? Lead to code difficult to understand and difficult to change, especially for global instance, the global instance discrete sex too, scattered in every corner of the entire project, the most important details of the code we write is also hidden among objects interactive, some examples would include references to other instance, if there are problems, we can only read through every line of code. We dependency injection instead of through the introduction of a global way of example, via dependency injection common way that the constructor injection dependency injection parameters, which will improve the readability of the code, we need to quickly browse the constructor to view the corresponding dependencies. By introducing dependency injection we need to pay attention it is to be a reasonable division of the corresponding class, because each time a new dependency is introduced, may still exist dependencies between class and class, the different behavior into different groups, so that it can reduce the class coupling between classes, it makes our design more cohesive. By introducing more convenient dependency injection unit also allows us during testing, the test because we can directly through the isolation instance of class Class.

Inversion of Control Code Description 

Next, we discuss how to use the program to achieve under inversion of control, inversion of control to achieve the two most common ways are: Service Locator pattern (SL) and dependency injection pattern (DI). Next we realize injection control and dependency inversion mode locator service using by way of example. We achieved via the console get a list of books the library database, query books we want, we define the following categories of books:

    public class Book
    {
        /// <summary>
        /// 
        /// </summary>
        public int Id { get; set; }
        /// <summary>
        /// 
        /// </summary>
        public string Title { get; set; }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="arg"></param>
        /// <returns></returns>
        public bool GetAuthor(string arg)
        {
            return Title.Equals(arg);
        }
    }

Next, we will modify the console then the program name for the library database, then query based on books and print books we enter, pseudo-code is as follows:

    class Library
    {
        static void Main(string[] args)
        {
            var books = bookFinder.FindAll();
  
foreach (var book in books) { if (!book.GetAuthor(args[0])) continue; Console.WriteLine(book.Title); }; Console.ReadKey(); } }

As we get through bookFinder Library list, and then enter the name of our inquiry book and print, we glance this bookFinder come from? We may find the Shenzhen Library or the National Library or online remote crawling it? So then we need to create the interface bookFinder, as follows:

    ///  <Summary> 
    /// Query the book list
     ///  </ Summary> 
    public  interface IBookFinder 
    { 
        List <Book> the FindAll (); 
    }
    
    /// <summary>
    /// 深圳图书馆库
    /// </summary>
    public class ShenZhenLibraryBookFinder : IBookFinder
    {
        public List<Book> FindAll()
        {
           ......
        }
    }

    public class Library
    {
        private IBookFinder _bookFinder;

        public Library()
        {
            _bookFinder = new ShenZhenLibraryBookFinder();
        }

        public IEnumerable<Book> BooksAuthoredBy(string title)
        {
            var allBooks = _bookFinder.FindAll();

            foreach (var book in allBooks)
            {
                if (!book.GetAuthor(title)) continue;

                yield return book;
            }
        }
    }

After the above transformation, we provide IBookFinder interface and its implementation, but now we are being used as a framework needs to be scalable and others to use, if at this time need to provide to the National Library to use it? At this point we can see the library that is simultaneously dependent IBookFinder Library and its realization, when we as a scalable framework, the best results are dependent on the interface rather than relying on specific implementation details, then the time that instance we in the end how to use it? The answer is the inversion of control, dependency injection to achieve through our inversion of control.

    public class BookFinder
    {
        public IBookFinder ProvideShenZhenBookFinder()
        {
            return new ShenZhenLibraryBookFinder();
        }

        public IBookFinder ProvideNationalBookFinder()
        {
            return new NationalLibraryBookFinder();
        }
    }
    ///  <the Summary> 
    /// National Library Library
     ///  </ the Summary> 
    public  class NationalLibraryBookFinder: IBookFinder 
    { 
        public List <Book> the FindAll () 
        { 
            Console.WriteLine ( " Welcome to the National Library! " );
             return  new new List <Book> () {
                 new new Book () {Id = 1 , the Title = " strategic thinking " } 
            }; 
        } 
    } 

    ///  <the Summary> 
    /// Shenzhen library library
     /// </ the Summary> 
    public  class ShenZhenLibraryBookFinder: IBookFinder 
    { 
        public List <Book> the FindAll () 
        { 
            Console.WriteLine ( " Welcome to the Shenzhen Library! " );
             return  new new List <Book> () {
                 new new Book () {Id = . 1 , the Title = " moon and sixpence " } 
            }; 
        } 
    }

Next, we will modify the above Library Library Library is injected IBookFinder interface via the constructor, only this time the library will only depend on IBookFinder interfaces, internal IBookFinder realization Library does not care, then call the console as follows:

            var bookFinder = new BookFinder (); 

            var shenzhenBookFinder = new Library (bookFinder.ProvideShenZhenBookFinder ()); 

            var books = shenzhenBookFinder.BooksAuthoredBy (args [ 0 ]);

Through the above-described dependency injection can be extended so that we need only provide IBookFinder depending on the specific implementation library can, dependency injection is not the only way to achieve inversion of control, we can also be achieved by the service locator service locator behind the device is an object that knows how to get all the service applications that may be required, which means that the locator service provided to achieve our return IBookFinder interface, as follows:

    ///  <Summary> 
    /// service locator
     ///  </ Summary> 
    public  class the ServiceLocator 
    { 
        ///  <Summary> 
        /// store or retrieve service registration
         ///  </ Summary> 
        Private the IDictionary < String , Object > = Services new new the Dictionary < String , Object > (); 

        Private  static the serviceLocator _serviceLocator; 

        public  static  void the Load (the serviceLocator serviceLocator) 
        { 
            _serviceLocator = serviceLocator;
        }

        /// <summary>
        /// 获取服务
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public static object GetService(string key)
        {
            _serviceLocator.services.TryGetValue(key, out var service);

            return service;
        }

        /// <summary>
        /// 加载服务
        /// </summary>
        /// <param name="key"></param>
        /// <param name="service"></param>
        public void LoadService(string key, object service)
        {
            services.Add(key, service);
        }
    }
            ServiceLocator locator = new ServiceLocator (); 
            locator.LoadService (nameof (ShenZhenLibraryBookFinder), new ShenZhenLibraryBookFinder ()); 
            locator.LoadService (nameof (NationalLibraryBookFinder), new NationalLibraryBookFinder ()); 
            ServiceLocator.Load (locator); 

            var finder = (IBookFinder) ServiceLocator.GetService (nameof (ShenZhenLibraryBookFinder)); 

            var shenzhenBookFinder = new Library (finder); 

            var books = shenzhenBookFinder.BooksAuthoredBy (args [ 0 ]);

Via dependency injection and service locator implementations inversion of control are separated interdependence, dependency injection just let us glance through the constructor can view dependencies, and service locators need to explicitly request dependence, there is no difference in essence, As for how to use, it depends on our familiarity with both. As Martin Fowler said: When using the service locator, each service depends on the service locator, which can be hidden to other dependencies to achieve, but we do need to see the locator service, therefore, whether the use of locator or injector It depends mainly on whether the dependency problem. Here we talked about IServiceProvider interface is implemented by means of .NET Core service locator. as follows:

    public class ServiceLocator
    {
        public static IServiceProvider Instance;
    }

In addition to the above wording, we can also get the service by instantiating ServiceLocator way, as follows:

    public class ServiceLocator
    {
        private IServiceProvider _currentServiceProvider;
        private static IServiceProvider _serviceProvider;

        public ServiceLocator(IServiceProvider currentServiceProvider)
        {
            _currentServiceProvider = currentServiceProvider;
        }

        public static ServiceLocator Current
        {
            get
            {
                return new ServiceLocator(_serviceProvider);
            }
        }

        public static void SetLocatorProvider(IServiceProvider serviceProvider)
        {
            _serviceProvider = serviceProvider;
        }

        public T GetService<T>()
        {
            return _currentServiceProvider.GetRequiredService<T>();
        }
    }

    /// <summary>
    /// IServiceProvider扩展方法
    /// </summary>
    public static class ServiceProviderExtensions
    {
        public static T GetRequiredService<T>(this IServiceProvider provider)
        {
            var serviceType = typeof(T);
           
            if (provider is ISupportRequiredService requiredServiceSupportingProvider)
            {
                return (T)requiredServiceSupportingProvider.GetRequiredService(serviceType);
            }

            var service = (T)provider.GetService(serviceType);

            if (service == null)
            {
                throw new InvalidOperationException($"{serviceType} no registered");
            }

            return service;
        }
    }

Next we write a simple interface to verify correct:

    public interface IHelloWorld
    {
        string Say();
    }

    public class HelloWorld : IHelloWorld
    {
        public string Say()
        {
            return "Hello World";
        }
    }

 

不知道上述两种写法是否存在有什么不妥的地方,有的时候通过服务定位器的方式也非常清爽,因为当我们实例化最终具体实现时通过构造注入依赖项时,本没有什么,但是若后期一旦需要增加或减少依赖项时,我们同样需要修改最终具体实现,像这种情况是否可以考虑用服务定位器模式,直接通过服务定位器去获取指定服务,当在具体方法里时我们每次都得去获取服务,反而不如在构造器中一劳永逸注入。所以选择注入器和定位器根据个人而选择或者根据具体功能实现而定才是最佳。 

控制反转举栗说明 

Through the above code in the form of further elaborated Inversion of Control, in the world of code, we use inversion of control capability, in real life, we use inversion of control is handy. End is approaching, the whole family gathered together, this should be the year's most popular family gathering it, in order to prepare a festive dinner exactly which ingredients and food should be provided as part of the family had to have a basic understanding, so we must be prepared in advance these, it's like we do not write a basic program like dependency injection, which is the case at home do their own cooking after eating, wiped his mouth can not oiled, Paipaipigu leave immediately, not have to clean up Ever since we place a festive dinner will be switched to the hotel, this time we owned a hotel similar to the banned ingredients this one, just like the hotel caterer, we do not do it yourself, the hotel will provide us with food, it will be according to our injection of the different needs of different catering services. From home - "Hotel, reversing the entire process control, we will hand over control of a festive dinner in a restaurant, because the hotel has become a festive dinner planners of this event, it is a necessary condition if we can successfully eat a festive dinner, we told the restaurant owner: several people, with the children, need to taste a little heavier, and so on, we need to do is provide some basic parameters, then the hotel will be self-organized, we do not need to care about the details and interference, they will deal with all the problems, When everything is ready we will inform us.

to sum up 

This article has been written for the purpose of Inversion of Control and Dependency Injection do not understand, in my mind has been in a vague concept, and then, before the interviewer asked me about dependency injection understand, I actually hesitated to say Dependency Inversion principles (dependency inversion principle), Never dependency injection, dependency inversion, inversion of control, confused, dependency inversion principle is completely different, loosely coupled and reverse dependencies although it can also be provided between classes. If the text of the error, but also look pointed out, thank you for reading, thank you.

Guess you like

Origin www.cnblogs.com/CreateMyself/p/12037874.html