对DIP、IoC、DI、IoC容器的解释,静下心,认真看完就能理解
来源:互联网 发布:如何评价pdd人品 知乎 编辑:程序博客网 时间:2024/06/08 12:21
1、基本概念总结:
<1>、hibernate:
hibernate比较常用的环境是ORM机制,就是将传统的关系型数据库,转化为面向对象编程思想来操作操作数据库。
举个例子来解释:例如一个表单上有名字、年龄、爱好、性别。。。。等许多的关键字,在没有使用ORM机制之前,你需要
为这些字段的内容分别创建一个变量来进行保存,然后再一条条的写sql语句,这样会很麻烦,做很多重复的工作,而在你
使用了hibernate中的ORM机制以后,就会将数据库中的表映射为一个对象,然后在表单对应的input的name上,填写对应对
象的对应属性,然后在保存的时候,在提交到的action中,定义一个student的对象实例,那么这些数据就会自动保存在这个
对象之中了。接下来你就只需要保存一下这个对象就可以了,而不再需要一条一条的进行保存了。
<2>、SessionFactory:(顾名思义,就是产生session的工厂)
SessionFactory接口负责初始化hibernate。它充当数据存储源的代理,并负责创建session对象。
<3>、Session:
这里要注意一下,hibernate中的session并不是http中的session。HttpSession对象称为用户会话。
而hibernate中的session是用来表示,应用程序和数据库的一次会话。通常将每个session实例和一个数据库事务绑定,也
就是每执行一个数据库事务,都应该先创建一个新的Session实例,在使用Session之后,要记得关闭session。
<4>、DIP依赖倒置原则:
依赖倒置原则:一种软件架构设计的原则。
具体形象的例子:比如说生活中应用到的atm取款机和银行卡,众所周知,任何一张银行卡都可以从个大银行的atm取款机取
款,银行卡的设计规则是依据各个atm取款机统一的设计规则来设计的,而不是atm根据银行卡来设计在这个例子中,ATM相当于高
层模块,而银行卡相当于底层模块。也就是说ATM不依赖于具体的哪种银行卡,它只需要定义好银行卡的规则参数(接口),所有实现
了这种规格参数的银行卡都可以在ATM上使用.所以,在软件设计方面,依赖倒置原则,它转换了依赖,高层模块不再依赖于底层模块
的实现,而底层模块依赖于高层模块定义的接口。通俗的讲,就是高层模块定义接口,底层模块负责实现。
使用接口实现而不是继承的原因:在类的继承中,只能做单重继承,而实现接口时,一次可以实现多个接口。
如果底层模块设定接口,那么当有新的底层模块类出现的时候,高层模块就会需要修改代码,来实现新的底层模块的接口。这样,
就破坏了开发封闭的原则。
·总结:DIP的优点:
(1)、系统更柔韧:可以修改一部分代码而不影响其他的模块。
(2)、系统更健壮:可以修改一部分代码而不会让系统崩溃。
(3)、系统更高效:组件松耦合,且可以复用,提高开发效率。
<5>、控制反转Ioc:
控制反转(IoC):一种反转流、依赖和接口的方式(DIP的具体实现方式)。
DIP是一种软件架构的设计原则:高层模块不应该依赖于底层模块.它只告诉了你一种设计原则,但是并没有告诉你如何去做.
Ioc控制反转就是一种设计模式,它就来告诉你如何去做,来解除相互依赖模块的耦合。
·控制反转(IoC):它为相互依赖的组件提供抽象,将依赖(底层模块)对象的获取交给第三方(系统)来控制,也就是说不在高层模块
中进行获取底层模块对象的操作,即依赖对象不在被依赖模块的类中直接通过new来获取。
例如:ATM自身并没有插入具体的银行卡,而是将插卡的操作交给人来完成。在软件设计中就是把依赖对象的实例化操作交给第三
方来完成。
·设计原则:原则为我们提供指南,它告诉我们什么是对的,什么是错的。它不会告诉我们如何解决问题。它仅仅给出一些准则,
以便我们可以设计好的软件,避免不良的设计。一些常见的原则,比如DRY、OCP、DIP等。
·设计模式:模式是在软件开发过程中总结得出的一些可重用的解决方案,它能解决一些实际的问题。一些常见的模式,比如工
厂模式、单例模式等等
·总结:高层模块的类不应该依赖于底层模块,而两者应该依赖于抽象(抽象类不能够实例化)。为了实现这种设计原则,我们可以使用
Ioc来优化代码。Ioc有两种常见的实现方式:依赖注入和服务定位。
·注解:解释抽象类:
对于普通方法,有"{}"表示方法体,有了方法体就可以进行实例化,而当没有方法体的时候,就表示的是抽象方法,抽象方法
不能够进行实例化。有抽象方法的类就表示抽象类。抽象类不能够进行实例化,可以继承进行覆写。
·对于类和接口的一些关系,遵循以下原则(不管是抽象类还是实体类都遵从以下原则):
1、接口只能继承接口,还可以继承多个接口,用逗号隔开。接口不能继承类。
2、类只能实现接口,还可以实现多个接口。类能够继承类,只能继承一个类。 、
<6>、依赖注入(DI).
是一种反转方式,是一种Ioc设计模式的具体方式。
控制反转(Ioc)是一种重要的方式,就是说把依赖对象的创建和绑定转移到被依赖对象类的外部来实现(第三方,外部即系统来完成)。
·依赖注入(ID):它提供一种机制,将需要依赖(底层模块)对象的引用传递给被依赖(高层模块)对象。
所谓的引用就是new出的一个对象的对象名,实质是地址。
·依赖注入DI有三种方式:构造函数注入,属性注入,接口注入。
(1)、构造函数注入:
|-:原先代码(订单入库的设计):
1)、我们会先定义一个SqlServletDal类,用于数据库的读写:
public class SqlServletDal{
public void Add(){
Console.WriteLine("在数据库中添加一条订单!");
}
}
2)、然后我们定义一个Order类,用于完成订单入库的逻辑处理。
public class Order{
private readonly SqlServerDal dal = new SqlServerDal();//添加一个私有变量保存数据库操作的对象
public void Add(){
dal.Add();
}
}
!!!注意:这个类就相当于是高层模块,我们的设计原则就是在上线以后最好不要改变这个类。
3)、然后我们写一个控制台程序来检验成果:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace DIPTest{
class Program{
static void Main(string[] args){
Order order = new Order();
order.Add();
Console.Read();
}
}
}
·对于这种代码的不好之处就是,当boss要求换成另外一种数据库的时候,需要改高层模块:
4)、如果要用Access数据库,需要再重新定义一个类,然后还得改Order类:
public class AccessDal{
public void Add(){
Console.WriteLine("在ACCESS数据库中添加一条记录!");
}
}
public class Order{
private readonly AccessDal dal = new AccessDal();//添加一个私有变量保存数据库操作的对象
public void Add(){
dal.Add();
}
}
|-:使用DI构造方法注入:
1)、因为设计原则是高层模块和底层模块之间的耦合靠的是抽象,所以我们先需要定义SqlServerDal的抽象类型
IDataAccess,并在IDataAccess接口中声明一个Add方法。
public interface IDataAccess{
void Add();
}
2)、然后在SqlServerDal类中,实现IDataAccess接口。
public class SqlServerDal:IDataAccess{
public void Add(){
Console.WriteLine("在数据库中添加一条订单!");
}
}
3)、修改Order类:
public class Order{
private IDataAccess _ida;//定义一个私有变量保存抽象
//构造函数注入
public Order(IDataAccess ida){
_ida = ida;//传递依赖
}
public void Add(){
_ida.Add();
}
}
!!!注意:这样写完之后,以后再修改数据库的话,就不在需要改这个类了。也就是说依赖的注入不在被依赖的类中完成,
而是在外部完成。
4)、控制台程序。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace DIPTest{
class Program{
static void Main(string[] args){
SqlServerDal dal = new SqlServerDal();//在外部创建依赖对象
Order order = new Order(dal);//通过构造函数注入依赖,通过引用来注入。
order.Add();
Console.Read();
}
}
}
5)、如果使用Access数据库的话:
public class AccessDal:IDataAccess
{
public void Add()
{
Console.WriteLine("在ACCESS数据库中添加一条记录!");
}
}
然后在控制台程序中重新绑定依赖关系:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace DIPTest
{
class Program
{
static void Main(string[] args)
{
AccessDal dal = new AccessDal();//在外部创建依赖对象
Order order = new Order(dal);//通过构造函数注入依赖
order.Add();
Console.Read();
}
}
}
注解:显然,我们不需要修改Order类的代码,就完成了Access数据库的移植,这无疑体现了IoC的精妙。
(2)、属性注入:
1)、 顾名思义,属性注入是通过属性来传递依赖。因此,我们首先需要在依赖类Order中定义一个属性:
public class Order
{
private IDataAccess _ida;//定义一个私有变量保存抽象
//属性,接受依赖
public IDataAccess Ida
{
set { _ida = value; }
get { return _ida; }
}
public void Add()
{
_ida.Add();
}
}
2)、然后在控制台程序中,给属性赋值,从而传递依赖:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace DIPTest
{
class Program
{
static void Main(string[] args)
{
AccessDal dal = new AccessDal();//在外部创建依赖对象
Order order = new Order();
order.Ida = dal;//给属性赋值
order.Add();
Console.Read();
}
}
}
我们可以得到上述同样的结果。
(3)、注入接口实现:
1)、相比构造函数注入和属性注入,接口注入显得有些复杂,使用也不常见。具体思路是先定义一个接口,
包含一个设置依赖的方法。然后依赖类,继承并实现这个接口。
首先定义一个接口:
public interface IDependent
{
void SetDependence(IDataAccess ida);//设置依赖项
}
2)、依赖类实现这个接口:
public class Order : IDependent
{
private IDataAccess _ida;//定义一个私有变量保存抽象
//实现接口
public void SetDependence(IDataAccess ida){
_ida = ida;
}
public void Add(){
_ida.Add();
}
}
3)、控制台程序通过SetDependence方法传递依赖:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace DIPTest{
class Program{
static void Main(string[] args){
AccessDal dal = new AccessDal();//在外部创建依赖对象
Order order = new Order();
order.SetDependence(dal);//传递依赖
order.Add();
Console.Read();
}
}
}
我们同样能得到上述的输出结果。
<7>、Ioc容器。
Ioc容器是一种框架,是依赖注入的框架,用来映射依赖,管理对象创建和生存周期(DI框架)。
在前面,我们是通过手动的方式来创建依赖对象,并将引用传递给依赖模块.例如:
SqlServerDal dal = new SqlServerDal();//在外部创建依赖对象
Order order = new Order(dal);//通过构造函数注入依赖
·对于大型项目来说,相互依赖的组件比较多。如果还用手动的方式,自己来创建和注入依赖的话,
显然效率很低,而且往往还会出现不可控的场面。正因如此,IoC容器诞生了。IoC容器实际上是一
个DI框架,它能简化我们的工作量。它包含以下几个功能:
(1)、动态创建、注入依赖对象。
(2)、管理对象生命周期。
(3)、映射依赖关系。
<8>、总结:
DIP是软件的一种设计思想,Ioc就是实现该设计思想的一种设计模式,DI即使实现该模式的具体方法之一,
Io容器是DI实现的框架,它管理着依赖项的生命周期以及映射关系。
·依赖倒置原则(DIP):一种软件架构设计的原则(抽象概念)。
·控制反转(IoC):一种反转流、依赖和接口的方式(DIP的具体实现方式)。
·依赖注入(DI):IoC的一种实现方式,用来反转依赖(IoC的具体实现方式)。
·IoC容器:依赖注入的框架,用来映射依赖,管理对象创建和生存周期(DI框架)。
<1>、hibernate:
hibernate比较常用的环境是ORM机制,就是将传统的关系型数据库,转化为面向对象编程思想来操作操作数据库。
举个例子来解释:例如一个表单上有名字、年龄、爱好、性别。。。。等许多的关键字,在没有使用ORM机制之前,你需要
为这些字段的内容分别创建一个变量来进行保存,然后再一条条的写sql语句,这样会很麻烦,做很多重复的工作,而在你
使用了hibernate中的ORM机制以后,就会将数据库中的表映射为一个对象,然后在表单对应的input的name上,填写对应对
象的对应属性,然后在保存的时候,在提交到的action中,定义一个student的对象实例,那么这些数据就会自动保存在这个
对象之中了。接下来你就只需要保存一下这个对象就可以了,而不再需要一条一条的进行保存了。
<2>、SessionFactory:(顾名思义,就是产生session的工厂)
SessionFactory接口负责初始化hibernate。它充当数据存储源的代理,并负责创建session对象。
<3>、Session:
这里要注意一下,hibernate中的session并不是http中的session。HttpSession对象称为用户会话。
而hibernate中的session是用来表示,应用程序和数据库的一次会话。通常将每个session实例和一个数据库事务绑定,也
就是每执行一个数据库事务,都应该先创建一个新的Session实例,在使用Session之后,要记得关闭session。
<4>、DIP依赖倒置原则:
依赖倒置原则:一种软件架构设计的原则。
具体形象的例子:比如说生活中应用到的atm取款机和银行卡,众所周知,任何一张银行卡都可以从个大银行的atm取款机取
款,银行卡的设计规则是依据各个atm取款机统一的设计规则来设计的,而不是atm根据银行卡来设计在这个例子中,ATM相当于高
层模块,而银行卡相当于底层模块。也就是说ATM不依赖于具体的哪种银行卡,它只需要定义好银行卡的规则参数(接口),所有实现
了这种规格参数的银行卡都可以在ATM上使用.所以,在软件设计方面,依赖倒置原则,它转换了依赖,高层模块不再依赖于底层模块
的实现,而底层模块依赖于高层模块定义的接口。通俗的讲,就是高层模块定义接口,底层模块负责实现。
使用接口实现而不是继承的原因:在类的继承中,只能做单重继承,而实现接口时,一次可以实现多个接口。
如果底层模块设定接口,那么当有新的底层模块类出现的时候,高层模块就会需要修改代码,来实现新的底层模块的接口。这样,
就破坏了开发封闭的原则。
·总结:DIP的优点:
(1)、系统更柔韧:可以修改一部分代码而不影响其他的模块。
(2)、系统更健壮:可以修改一部分代码而不会让系统崩溃。
(3)、系统更高效:组件松耦合,且可以复用,提高开发效率。
<5>、控制反转Ioc:
控制反转(IoC):一种反转流、依赖和接口的方式(DIP的具体实现方式)。
DIP是一种软件架构的设计原则:高层模块不应该依赖于底层模块.它只告诉了你一种设计原则,但是并没有告诉你如何去做.
Ioc控制反转就是一种设计模式,它就来告诉你如何去做,来解除相互依赖模块的耦合。
·控制反转(IoC):它为相互依赖的组件提供抽象,将依赖(底层模块)对象的获取交给第三方(系统)来控制,也就是说不在高层模块
中进行获取底层模块对象的操作,即依赖对象不在被依赖模块的类中直接通过new来获取。
例如:ATM自身并没有插入具体的银行卡,而是将插卡的操作交给人来完成。在软件设计中就是把依赖对象的实例化操作交给第三
方来完成。
·设计原则:原则为我们提供指南,它告诉我们什么是对的,什么是错的。它不会告诉我们如何解决问题。它仅仅给出一些准则,
以便我们可以设计好的软件,避免不良的设计。一些常见的原则,比如DRY、OCP、DIP等。
·设计模式:模式是在软件开发过程中总结得出的一些可重用的解决方案,它能解决一些实际的问题。一些常见的模式,比如工
厂模式、单例模式等等
·总结:高层模块的类不应该依赖于底层模块,而两者应该依赖于抽象(抽象类不能够实例化)。为了实现这种设计原则,我们可以使用
Ioc来优化代码。Ioc有两种常见的实现方式:依赖注入和服务定位。
·注解:解释抽象类:
对于普通方法,有"{}"表示方法体,有了方法体就可以进行实例化,而当没有方法体的时候,就表示的是抽象方法,抽象方法
不能够进行实例化。有抽象方法的类就表示抽象类。抽象类不能够进行实例化,可以继承进行覆写。
·对于类和接口的一些关系,遵循以下原则(不管是抽象类还是实体类都遵从以下原则):
1、接口只能继承接口,还可以继承多个接口,用逗号隔开。接口不能继承类。
2、类只能实现接口,还可以实现多个接口。类能够继承类,只能继承一个类。 、
<6>、依赖注入(DI).
是一种反转方式,是一种Ioc设计模式的具体方式。
控制反转(Ioc)是一种重要的方式,就是说把依赖对象的创建和绑定转移到被依赖对象类的外部来实现(第三方,外部即系统来完成)。
·依赖注入(ID):它提供一种机制,将需要依赖(底层模块)对象的引用传递给被依赖(高层模块)对象。
所谓的引用就是new出的一个对象的对象名,实质是地址。
·依赖注入DI有三种方式:构造函数注入,属性注入,接口注入。
(1)、构造函数注入:
|-:原先代码(订单入库的设计):
1)、我们会先定义一个SqlServletDal类,用于数据库的读写:
public class SqlServletDal{
public void Add(){
Console.WriteLine("在数据库中添加一条订单!");
}
}
2)、然后我们定义一个Order类,用于完成订单入库的逻辑处理。
public class Order{
private readonly SqlServerDal dal = new SqlServerDal();//添加一个私有变量保存数据库操作的对象
public void Add(){
dal.Add();
}
}
!!!注意:这个类就相当于是高层模块,我们的设计原则就是在上线以后最好不要改变这个类。
3)、然后我们写一个控制台程序来检验成果:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace DIPTest{
class Program{
static void Main(string[] args){
Order order = new Order();
order.Add();
Console.Read();
}
}
}
·对于这种代码的不好之处就是,当boss要求换成另外一种数据库的时候,需要改高层模块:
4)、如果要用Access数据库,需要再重新定义一个类,然后还得改Order类:
public class AccessDal{
public void Add(){
Console.WriteLine("在ACCESS数据库中添加一条记录!");
}
}
public class Order{
private readonly AccessDal dal = new AccessDal();//添加一个私有变量保存数据库操作的对象
public void Add(){
dal.Add();
}
}
|-:使用DI构造方法注入:
1)、因为设计原则是高层模块和底层模块之间的耦合靠的是抽象,所以我们先需要定义SqlServerDal的抽象类型
IDataAccess,并在IDataAccess接口中声明一个Add方法。
public interface IDataAccess{
void Add();
}
2)、然后在SqlServerDal类中,实现IDataAccess接口。
public class SqlServerDal:IDataAccess{
public void Add(){
Console.WriteLine("在数据库中添加一条订单!");
}
}
3)、修改Order类:
public class Order{
private IDataAccess _ida;//定义一个私有变量保存抽象
//构造函数注入
public Order(IDataAccess ida){
_ida = ida;//传递依赖
}
public void Add(){
_ida.Add();
}
}
!!!注意:这样写完之后,以后再修改数据库的话,就不在需要改这个类了。也就是说依赖的注入不在被依赖的类中完成,
而是在外部完成。
4)、控制台程序。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace DIPTest{
class Program{
static void Main(string[] args){
SqlServerDal dal = new SqlServerDal();//在外部创建依赖对象
Order order = new Order(dal);//通过构造函数注入依赖,通过引用来注入。
order.Add();
Console.Read();
}
}
}
5)、如果使用Access数据库的话:
public class AccessDal:IDataAccess
{
public void Add()
{
Console.WriteLine("在ACCESS数据库中添加一条记录!");
}
}
然后在控制台程序中重新绑定依赖关系:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace DIPTest
{
class Program
{
static void Main(string[] args)
{
AccessDal dal = new AccessDal();//在外部创建依赖对象
Order order = new Order(dal);//通过构造函数注入依赖
order.Add();
Console.Read();
}
}
}
注解:显然,我们不需要修改Order类的代码,就完成了Access数据库的移植,这无疑体现了IoC的精妙。
(2)、属性注入:
1)、 顾名思义,属性注入是通过属性来传递依赖。因此,我们首先需要在依赖类Order中定义一个属性:
public class Order
{
private IDataAccess _ida;//定义一个私有变量保存抽象
//属性,接受依赖
public IDataAccess Ida
{
set { _ida = value; }
get { return _ida; }
}
public void Add()
{
_ida.Add();
}
}
2)、然后在控制台程序中,给属性赋值,从而传递依赖:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace DIPTest
{
class Program
{
static void Main(string[] args)
{
AccessDal dal = new AccessDal();//在外部创建依赖对象
Order order = new Order();
order.Ida = dal;//给属性赋值
order.Add();
Console.Read();
}
}
}
我们可以得到上述同样的结果。
(3)、注入接口实现:
1)、相比构造函数注入和属性注入,接口注入显得有些复杂,使用也不常见。具体思路是先定义一个接口,
包含一个设置依赖的方法。然后依赖类,继承并实现这个接口。
首先定义一个接口:
public interface IDependent
{
void SetDependence(IDataAccess ida);//设置依赖项
}
2)、依赖类实现这个接口:
public class Order : IDependent
{
private IDataAccess _ida;//定义一个私有变量保存抽象
//实现接口
public void SetDependence(IDataAccess ida){
_ida = ida;
}
public void Add(){
_ida.Add();
}
}
3)、控制台程序通过SetDependence方法传递依赖:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace DIPTest{
class Program{
static void Main(string[] args){
AccessDal dal = new AccessDal();//在外部创建依赖对象
Order order = new Order();
order.SetDependence(dal);//传递依赖
order.Add();
Console.Read();
}
}
}
我们同样能得到上述的输出结果。
<7>、Ioc容器。
Ioc容器是一种框架,是依赖注入的框架,用来映射依赖,管理对象创建和生存周期(DI框架)。
在前面,我们是通过手动的方式来创建依赖对象,并将引用传递给依赖模块.例如:
SqlServerDal dal = new SqlServerDal();//在外部创建依赖对象
Order order = new Order(dal);//通过构造函数注入依赖
·对于大型项目来说,相互依赖的组件比较多。如果还用手动的方式,自己来创建和注入依赖的话,
显然效率很低,而且往往还会出现不可控的场面。正因如此,IoC容器诞生了。IoC容器实际上是一
个DI框架,它能简化我们的工作量。它包含以下几个功能:
(1)、动态创建、注入依赖对象。
(2)、管理对象生命周期。
(3)、映射依赖关系。
<8>、总结:
DIP是软件的一种设计思想,Ioc就是实现该设计思想的一种设计模式,DI即使实现该模式的具体方法之一,
Io容器是DI实现的框架,它管理着依赖项的生命周期以及映射关系。
·依赖倒置原则(DIP):一种软件架构设计的原则(抽象概念)。
·控制反转(IoC):一种反转流、依赖和接口的方式(DIP的具体实现方式)。
·依赖注入(DI):IoC的一种实现方式,用来反转依赖(IoC的具体实现方式)。
·IoC容器:依赖注入的框架,用来映射依赖,管理对象创建和生存周期(DI框架)。
阅读全文
0 0
- 对DIP、IoC、DI、IoC容器的解释,静下心,认真看完就能理解
- 深入理解DIP、IoC、DI以及IoC容器
- 深入理解DIP、IoC、DI以及IoC容器
- 深入理解DIP、IoC、DI以及IoC容器
- 深入理解DIP、IoC、DI以及IoC容器
- 深入理解DIP、IoC、DI以及IoC容器
- 深入理解DIP、IoC、DI以及IoC容器
- 深入理解DIP、IoC、DI以及IoC容器
- 深入理解DIP、IoC、DI以及IoC容器
- 深入理解DIP、IoC、DI以及IoC容器
- 深入理解DIP、IoC、DI以及IoC容器
- 深入理解DIP、IoC、DI以及IoC容器
- 深入理解DIP、IoC、DI以及IoC容器
- 深入理解DIP、IoC、DI以及IoC容器
- 深入理解DIP、IoC、DI以及IoC容器
- 深入理解DIP、IoC、DI以及IoC容器
- 深入理解DIP、IoC、DI以及IoC容器
- 深入理解DIP、IoC、DI以及IoC容器
- Map集合
- Java8 新特性之Stream----java.util.stream
- beginning spring boot 2.pdf 英文原版免费下载
- 剑指offer之二叉树的深度(Python)
- 文章标题
- 对DIP、IoC、DI、IoC容器的解释,静下心,认真看完就能理解
- JAVA发展简史
- OpenResty安装(Centos7.2)
- mysql索引
- It's not a Bug, it's a Feature! UVA
- 理解梯度下降,随机梯度下降,附电影推荐系统的简单代码小样 2
- iscsi架构分析
- 我的第一个C博客
- 模电解析 第二章 选择题&判断题