Inversion of Control
InversionOfControl
https://martinfowler.com/bliki/InversionOfControl.html
中文翻译,控制反转。
当你的软件控制逻辑变得复杂的时候, 控制层适合独立出来单独进行管理。
一些框架或者IOC容器,提供了这种能力。
所以确认一个软件包是库还是框架, 则控制层是否抽出到软件包中是一个重要的判断标志。
例如
itertools是一个库,其实若干功能函数的集合,
flask是一个框架,可以独立运行,负责处理http请求。
原文中对 命令行界面 和 GUI 界面做的对比。
命令行的输入存储的控制,都在单体程序中;
但是GUI界面做了分析, 其只对输入数据的收集负责, 业务程序负责监听数据收集事件, 并调用响应的业务处理程序,包括存储数据。
这里的反转可以理解为, 代码不用自己处理控制逻辑, 这些逻辑交由 GUI框架来负责;
即,我们的程序逻辑被框架(或者是自己写的框架控制逻辑代码)控制;
即,程序代码从控制的一方,转变为被控制的一方,这可以理解为反转。
Inversion of Control is a common phenomenon that you come across when extending frameworks. Indeed it's often seen as a defining characteristic of a framework.
Let's consider a simple example. Imagine I'm writing a program to get some information from a user and I'm using a command line enquiry. I might do it something like this
#ruby puts 'What is your name?' name = gets process_name(name) puts 'What is your quest?' quest = gets process_quest(quest)In this interaction, my code is in control: it decides when to ask questions, when to read responses, and when to process those results.
However if I were were to use a windowing system to do something like this, I would do it by configuring a window.
require 'tk' root = TkRoot.new() name_label = TkLabel.new() {text "What is Your Name?"} name_label.pack name = TkEntry.new(root).pack name.bind("FocusOut") {process_name(name)} quest_label = TkLabel.new() {text "What is Your Quest?"} quest_label.pack quest = TkEntry.new(root).pack quest.bind("FocusOut") {process_quest(quest)} Tk.mainloop()There's a big difference now in the flow of control between these programs - in particular the control of when the
process_name
andprocess_quest
methods are called. In the command line form I control when these methods are called, but in the window example I don't. Instead I hand control over to the windowing system (with theTk.mainloop
command). It then decides when to call my methods, based on the bindings I made when creating the form. The control is inverted - it calls me rather me calling the framework. This phenomenon is Inversion of Control (also known as the Hollywood Principle - "Don't call us, we'll call you").
框架含有控制逻辑。
业务代码只服务具体的业务。
Inversion of Control is a key part of what makes a framework different to a library. A library is essentially a set of functions that you can call, these days usually organized into classes. Each call does some work and returns control to the client.
A framework embodies some abstract design, with more behavior built in. In order to use it you need to insert your behavior into various places in the framework either by subclassing or by plugging in your own classes. The framework's code then calls your code at these points.
Pros
https://en.wikipedia.org/wiki/Inversion_of_control
增加模块性, 使得程序更加具有扩展性。
Inversion of control is used to increase modularity of the program and make it extensible,[1] and has applications in object-oriented programming and other programming paradigms. The term was used by Michael Mattsson in a thesis,[2] taken from there[3] by Stefano Mazzocchi and popularized by him in 1999 in a defunct Apache Software Foundation project, Avalon, then further popularized in 2004 by Robert C. Martin and Martin Fowler.
与依赖倒置关系?
https://en.wikipedia.org/wiki/Inversion_of_control
依赖倒置关注高层和底层的依赖解耦, 通过定义一个抽象的中间层;
IoC关注公共逻辑抽取,并提供事件驱动模式行为, 例如事件的callback来处理业务。
The term is related to, but different from, the dependency inversion principle, which concerns itself with decoupling dependencies between high-level and low-level layers through shared abstractions. The general concept is also related to event-driven programming in that it is often implemented using IoC so that the custom code is commonly only concerned with the handling of events, whereas the event loop and dispatch of events/messages is handled by the framework or the runtime environment.
控制反转
分为三种:
接口定义反转, 定义在下层模块的接口, 反转到上层模块, 上层模块依赖此新定义的接口。
流程反转, 将公共流程定义到上层模块。
依赖创建反转,程序不自己创建依赖,有框架创建依赖。
Inversion of Control (IoC)
DIP doesn’t tell us how to solve the problem but Inversion of Control defines some way so that we can maintain DIP. It is the thing which you can practically apply on your software development. Lots of definition available for IoC. Here I just try to give a simple definition so that we can easily understand.
What is IoC
IoC helps us to apply DIP. In simple IoC is Inverting the control of something by switching who control. Particular class or another module of the system will be responsible for creation object from outside. Inversion of control means we are changing the control from the normal way.
IoC and DIP
DIP says High level module should not depend on low level module and both should depend on abstraction. IoC is a way that provides abstraction. A way to change the control. IoC gives some ways to implement DIP. If you want to make independent higher level module from the lower level module, then you have to invert the control so that low level module is not controlling interface and creation of the object. Finally, IoC gives some way to invert the control.
Splitting IoC
We can split IoC in the following ways. (Description will be provided later.)
- Interface Inversion: Inverting interfaces
- Flow inversion: Invert the flow of control and it is the foundation idea of IoC which is similar to, "Don’t call us, we will call you."
- Creation Inversion: This is mostly used by developers. We will use it when we go to DI and IoC container.
Fitting Altogether (DIP, IoC and DI)
I am not making full curry here. Just consider the above image how everything together fits. This is the view how all things fit together. DI is not only the way of Dependency creation that’s why I have used “….” . There are many ways to implement Dependency creation. Here, I am just interested in DI. That’s why I have shown it in the figure and others are doted. At the top is DIP which is a way of designing software. It doesn’t sys how to make independent module. IoC provides some way of applying DPI principle. IoC doesn’t provide specific implementation. It gives some methods so that we can invert the control. If we want to invert control using Binding inversion or dependency creation, then we can achieve it by implementing dependency injection (DI).
依赖倒置
https://juejin.cn/post/6844903487579357191
例如下面例子,定义一个抽象的 车辆 类, 所有车辆继承此类, 而人只依赖 抽象得车辆类。
本来正常编码下,肯定会出现上层依赖底层的情况,而依赖倒置原则的应用则改变了它们之间依赖的关系,它引进了抽象。上层依赖于抽象,底层的实现细节也依赖于抽象,所以依赖倒置我们可以理解为依赖关系被改变,如果非常纠结于倒置这个词,那么倒置的其实是底层细节,原本它是被上层依赖,现在它倒要依赖与抽象的接口。
控制反转实现方法
https://www.opensource-techblog.com/inversion-of-control.html
At this point, It’s clear that IOC is a way to achieve a DIP (Dependency Inversion Principle). However, it’s still not clear who will provide the dependencies to the high-level module.
Certain design patterns help in this scenario. They will create and provide the low-level objects (dependencies) to a high-level module. Below is a list of design patterns that do this job.
- Dependency Injection
- Factory
- Service Locator
- Observer
- Template method
We will see how each of these design patterns helps manage the dependency and allow achieving Inversion of Control in separate blogs.
https://sexywp.com/inversion-of-control-ioc.htm
参考
https://stackoverflow.com/questions/3058/what-is-inversion-of-control
What is Inversion of Control?
If you follow these simple two steps, you have done inversion of control:
- Separate what-to-do part from when-to-do part.
- Ensure that when part knows as little as possible about what part; and vice versa.
There are several techniques possible for each of these steps based on the technology/language you are using for your implementation.
--
The inversion part of the Inversion of Control (IoC) is the confusing thing; because inversion is the relative term. The best way to understand IoC is to forget about that word!
--
Examples
- Event Handling. Event Handlers (what-to-do part) -- Raising Events (when-to-do part)
- Dependency Injection. Code that constructs a dependency (what-to-do part) -- instantiating and injecting that dependency for the clients when needed, which is usually taken care of by the DI tools such as Dagger (when-to-do-part).
- Interfaces. Component client (when-to-do part) -- Component Interface implementation (what-to-do part)
- xUnit fixture. Setup and TearDown (what-to-do part) -- xUnit frameworks calls to Setup at the beginning and TearDown at the end (when-to-do part)
- Template method design pattern. template method when-to-do part -- primitive subclass implementation what-to-do part
- DLL container methods in COM. DllMain, DllCanUnload, etc (what-to-do part) -- COM/OS (when-to-do part)
Python ABC
IoC第一功能是接口反转, 需要使用接口功能。
python没有接口概念, 可以使用 抽象基础类代替。
https://zhuanlan.zhihu.com/p/89549054
from abc import ABC from abc import abstractmethod ? ? class Database(ABC): def register(self, host, user, password): print("Host : {}".format(host)) print("User : {}".format(user)) print("Password : {}".format(password)) print("Register Success!") ? @abstractmethod def query(self, *args): """ 传入查询数据的SQL语句并执行 """ ? @staticmethod @abstractmethod def execute(sql_string): """ 执行SQL语句 """ class Component1(Database): def __init__(self, host, user, password): self.register(host, user, password) ? @staticmethod def execute(sql_string): print(sql_string) ? def query(self, *args): sql_string = "SELECT ID FROM db_name" self.execute(sql_string) ? ? class Component2(Database): def __init__(self, host, user, password): self.register(host, user, password) ? @staticmethod def execute(sql_string): print(sql_string) ? def query(self, *args): sql_string = "SELECT NAME FROM db_name" self.execute(sql_string) ? comp1 = Component1("00.00.00.00", "abc", "000000") comp2 = Component2("11.11.11.11", "ABC", "111111") comp1.query() comp2.query() ?