qg777钱柜误乐

热门关键词: qg777钱柜误乐

2018-01-18 Python 中实现接口编程

DI就是常说的依赖注入,那么究竟什么是依赖注入呢?

1. 首先明确接口的定义

在生活中,两个实体部分进行连接的部分就叫做接口。如同USB接口,等同于电脑和U盘的连接,确保在不同实体之间顺利连接。再比如不同的电脑厂家只要按照相同的USB接口进行生产。

依赖倒置、控制反转和依赖注入的区分

打个比方,电脑需要键盘和鼠标我们才能进行操作,这个‘需要’换句话说就是‘依赖’键盘和鼠标。

接口的好处

依赖倒置、控制反转和依赖注入的区分依赖倒置(Dependency Inversion Principle)、控制反转(Inversion of Control)和依赖注入(Dependency Injection)从思想来讲是统一的,或者说是类似的,有人也说它们是同一个东西。但是还是可以做一点区分:

那么,相应的,一个类需要另一个类才能进行作业,那么这也就是依赖。

1. 为不同类顺利交互提供标准

例如老师让A 和B 同学一起完成设计,模拟营业员和计算器的行为。A同学负责写计算器,B 同学负责营业员类

在没有定义接口的时候,

A同学先定义了Calculator类并且提供计算的方式:

public class calculator

{

    public double count(double salary,double bonus)

    {

    return salary + bonus;

    }

}

B 同学在不知道A同学的设计下写了一下代码

class Seller

{    

    String name; // 营业员的名字

    Calculator calculator;

    public Seller(String name, Calculator calculator)

    {

        super();

        this.name = name;

        this.calculator = calculator;

    }

// 营业员有被问价的行为

public void quote( double slalry,double bonus)

{

System.out.println(name + "您好,请支付" + calculator.countMoney(salary,bonus)+“元”)

}

}

B同学在使用A同学的类时,想当然的认为计算钱的方法叫countMoney。

实现接口的好处是

为保证A 和B 同学书写的类能正确交互,B同学 定义了一个接口,并要求A必须实现这个接口,接口的代码如下:

interface Icount

{

public double countMoney(double salary,double bonus);

}

这样A同学在写Calculator类时,实现接口时必须重写接口中的抽象方法。

A同学写的代码改成

public class calculator implements Icount

{

public double countMoney(double slalry,double bonus)

{

    return salary +bonus;

}

}

B同学改成组合该接口的类

class Seller

{

String name; //

ICount calculator; // 相当于虚类集成,重写虚函数(虚函数等于接口),继承接口的类相当于USB 产品,带有接口的类相当于电脑

public Seller(String name, ICount calculator)//由编译器runtime时决定

 {

 super();

 this.name = name;

 this.calculator = calculator;

}

public void quote( double slalry,double bonus)

{

System.out.println(name + "说:您好,请支付" + calculator.countMoney(salary,bonus)+

}

}

这样无论A同学的USB产品改成什么名字,都可以被B同学的电脑识别使用

代码的依赖性大大降低

依赖倒置原则      是进行软件设计时考虑遵循的一个原则。具体为:
      (1)上层模块不应该依赖于下层模块,它们共同依赖于一个抽象。
      (2)抽象不能依赖于具象,具象依赖于抽象。

控制反转      是软件运行时体现出来的一个特征:如果对象A运行时依赖于对象B,但A并不去创建B,而是从外界直接取得B。也就是说,一个对象并不是自己去创建它所依赖的其它对象。

依赖注入      是控制反转的一种实现手段。如上面的例子,B的取得并不需要A的干涉,而是利用某些框架在通过构造参数或属性设置来实现。

看一段代码:

2.依赖注入与控制反转

DI (设计代码模式) 

控制反转(IOC)--设计代码的思路

依赖倒置原则 -- 设计代码原则

终极目标是解耦(也就是减少代码的修改量(因需求变化时))

在调用一个类时,首先要实例化这个类,生成一个队长

如果写一个类时要调用其他类,这些其他类也要依赖其他类的实例化

依赖注入(IOC 容器),他把某个类(有复杂的依赖关系)放入到容器中,可以分析这个类的实例,相当于构建一个工厂帮你实现实例化

DI与IOC 是一个意思

例子:

a 依赖于b 但不控制b的创建和销毁,仅使用b,那么b的控制权交给a之外处理

上述就是控制反转,IOC关注的是对象该由谁来管理,实际是IOC 容器来管理

怎么解决控制反转呢, 用DI就可以

a 依赖b 必然需要b 的实例

  1. 通过a 的接口,把b传入

2.通过 a的构造,把b传入

3.通过设置a的属性,把b传入

IOC Container的产生是

随着DI 用的越来越多,要实现IOC,有很多重复的代码,那么诱人把实现IOC的代码打包成组件或者框架,避免人们重复造轮子

实现IOC的组件和框架就叫IOC Container

例子:

class Employee

{

Address address;

Employee(Address address)

{

    this.address =address;

}

}

上述例子没有用IOC 容器,如果注入IOC 容器,则在构造函数过程中自动从IOC容器中返回依赖的实例项。 构造函数都不用修改

=

IOC:Inversion of Control 控制反转
DI:Dependency Injection 依赖注入
控制反转,从字面意思来看,就是控制权又被动变主动,最后又变回被动。
举个例子:
你的主管要求你做一件事情,这个时候就存在这么几个过程:

 class Computer { protected $keyboard; public function __construct() { $this->$keyboard = new Keyboard(); } } 这里的Computer类依赖了键盘类。

3. python 接口的实现和依赖注入的实现

六 大 design principle 

A.单一责任原则(singelton)

B.开放封闭原则 OSP

对扩展开放,对修改关闭

C.里氏替换原则(LSP)

可以用派生类替换基类

D.接口分离原则(ISP)

对于接口进行分类避免一个接口的方法过多

(也就是说不要把所有的抽象方法写在一个接口上,使用多个接口有助于解耦)

E.依赖倒置原则(DIP)

尽量使用接口或者抽象类代替函数参数或者

F.依赖注入和控制反转

23 

  1. 主管命令你做事情(这个时候主动权在主管,你是被动的)
  2. 你接到命令做事情(这个时候主题是你,你是主动的,控制权在你手里)
  3. 你完成事情(这个时候主题依然是你,控制权在你手里)
  4. 报告主管做完事情(主动权又叫交到主管手里了)

好,既然我们已经知道了什么是依赖,那么什么是注入呢?

上面的整个过程就完成了一次IOC,从上面可以看出,IOC的基本思想是控制权的转换过程。
举个代码的例子:
假如有Class A,Class B,在A内部会初始化一个B,调用B的一个方法DoMethod

我们改造一下上面的代码:

public Class B{
public void DoMethod()
{
//do somthing;
}
}

public Class A
{
public void Excute()
{
B b=newB();
b.DoMethod();
}
}
 class Computer { protected $keyboard; public function __construct(Keyboard $keyboard) { $this->$keyboard = $keyboard; } } $computer = new Computer(new Keyboard; 这里的Computer类依赖注入了Keyboard类。

假如在Main函数中如下执行:
A a=newA();
a.Excute();
从这两行代码来看,事实上也存在一个IOC的过程,a——>b——>a,理解的关键点就在在A的内部调用Excute的时候,方法b.DoMethod的执行。
理解了IOC,我们再看一下DI。
从上面A调用B我们可以看出,在初始化一个A的实例时,也必须实例化一个B,也就是说如果没有B或者B出了问题,A就无法实例化,这就产生了一种依赖,就是A依赖B,这种依赖从设计的角度来说就是耦合,显然它是无法满足高内聚低耦合的要求的。这个时候就需要解耦,当然解耦有很多种方法,而DI就是其中一种。不管任何一种解耦方法,都不是说使A和B完全没有关系,而是把这种关系的实现变得隐晦,不那么直接,但是又很容易实现,而且易于扩展,不像上面的代码那样,直接new一个B出来。
那为什么我们总是把IOC和DI联系到一起呢?是因为DI的基本思想就是IOC,而体现IOC 思想的方法还有另外一个,那就是Service Locator,这个方法好像涉及到的很少。
DI,依赖注入,从字面意思就可以看出,依赖是通过外接注入的方式来实现的。这就实现了解耦,而DI的方式通常有三种,

关于依赖注入,我的理解是:

  1. 构造器注入
  2. 属性设置器注入
  3. 接口注入(我感觉接口注入是同时存在于上两种注入方式的,而不应该独立出来)
    以上的阐述只是为了先让我们能对IOC和DI有一个感性的理解,那么IOC真正解决的问题是什么呢?
    我们讲了那么多主动被动的问题,那我们是从什么视角来看待这个问题的呢?
    所谓为什么你是主动,而我不是主动呢?这就需要一个参照物,那这个参照物是什么呢?就是容器,在容器中来体现主动和被动。
    用白话来讲,就是由容器控制程序之间的关系,而非传统实现中,由程序代码直接操控。这也就是所谓“控制反转”的概念所在:控制权由应用代码中转到了外部容器,控制权的转移,是所谓“反转”,这是通常对IOC的一个解释。
    从容器的角度来看主动和被动,和由容器来控制程序之间的关系,应该是相通的,是一个意思。
    IOC要解决的就是程序之间调用的一个问题,它应该是一个思想层面的东西,是一个中心,就像一支乐队的指挥,而程序就是乐器,通过指挥来协调各种乐器,来演奏出美好的音乐来。
    以下文字参考:http://www.cnblogs.com/gooddasenlin/archive/2009/03/02/1401631.html
    Interface Driven Design 接口驱动
    接口驱动有很多好处,可以提供不同灵活的子类实现,增加代码稳定和健壮性等等,但是接口一定是需要实现的,也就是如下语句迟早要执行:AInterface a = new AInterfaceImp(); 这样一来,耦合关系就产生了。
    如:

所需要的类通过参数的形式传入的就是依赖注入。

理解了依赖注入,我们可以接着理解IOC。

Class A
{
AInterface a;
A(){}
aMethod()
{
a=newAInterfaceImp();
}
}

IOC是什么呢?

ClassA与AInterfaceImp就是依赖关系,如果想使用AInterface的另外一个实现就需要更改代码了。
当然我们可以建立一个Factory来根据条件生成想要的AInterface的具体实现,即:

中文叫控制反转。啥意思呢? 这个看明白了DI后就能很容易的理解了。

InterfaceImplFactory
{
AInterface create(Object condition)
{
if(condition=condA)
{
returnnewAInterfaceImpA();
}
elseif(condition=condB)
{
returnnewAInterfaceImpB();
}
else
{
returnnewAInterfaceImp();
}
}
}

通过DI我们可以看到,一个类所需要的依赖类是由我们主动实例化后传入类中的。

表面上是在一定程度上缓解了以上问题,但实质上这种代码耦合并没有改变。
通过IoC模式可以彻底解决这种耦合,它把耦合从代码中移出去,放到统一的XML文件中,通过一个容器在需要的时候把这个依赖关系形成,即把需要的接口实现注入到需要它的类中,这可能就是“依赖注入”说法的来源了。
IOC模式系统中,通过引入实现IOC模式的IOC容器,即可由IOC容器来管理对象的生命周期、依赖关系等,从而使得应用程序的配置和依赖性规范与实际的应用程序代码分开。其中一个特点就是通过文本的配置文件进行应用程序组件间相互关系的配置,而不用重新修改并编译具体的代码。
当前比较知名的IOC容器有:Pico Container、Avalon 、Spring、JBoss、HiveMind、EJB等。其中,轻量级的有Pico Container、Avalon、Spring、HiveMind等,超重量级的有EJB,而半轻半重的有容器有JBoss,Jdon等。
可以把IoC模式看做是工厂模式的升华,可以把IoC看作是一个大工厂,只不过这个大工厂里要生成的对象都是在XML文件中给出定义的,然后利用Java 的“反射”编程,根据XML中给出的类名生成相应的对象。从实现来看,IoC是把以前在工厂方法里写死的对象生成代码,改变为由XML文件来定义,也就是把工厂和对象生成这两者独立分隔开来,目的就是提高灵活性和可维护性。
IoC中最基本的Java技术就是“反射”编程。反射又是一个生涩的名词,通俗的说反射就是根据给出的类名(字符串)来生成对象。这种编程方式可以让对象在生成时才决定要生成哪一种对象。反射的应用是很广泛的,象Hibernate、String中都是用“反射”做为最基本的技术手段。
IoC最大的好处是什么?因为把对象生成放在了XML里定义,所以当我们需要换一个实现子类将会变成很简单(一般这样的对象都是现实于某种接口的),只要修改XML就可以了。
参考:http://www.cnblogs.com/niuniu1985/archive/2010/01/13/1646375.html

控制反转和这个有什么关系呢?

控制反转意思是说将依赖类的控制权交出去,由主动变为被动。

看一段laravel代码:

namespace AppHttpControllers;use IlluminateHttpRequest;class SessionController extends Controller{ public function login(Request $request) { //这就是IOC,我们不需要主动传入类了一切由laravel去实现 }}

看到这你可能有疑问了,这是怎么实现的呢?

这就是靠服务容器了,请往下接着看。

看了很多文章,我一致认为服务容器就是一种设计模式。

本文由qg777发布于编程,转载请注明出处:2018-01-18 Python 中实现接口编程

TAG标签:
Ctrl+D 将本页面保存为书签,全面了解最新资讯,方便快捷。