1.产生背景:
面向对象原则之一——开放封闭原则(OCP)的要求,即
一个模块在扩展性方面应该是开放的而在更改性方面应该是封闭的,即将变化隔离,使得变化部分发生变化时,不变部分不受影响。
为了做到这一点,要利用面向对象中的多态性,使用多态性后,客户类不再直接依赖服务类,而是依赖于一个抽象的接口,这样,客户类就不能在内部直接实例化具体的服务类。但是,客户类在运作中又客观需要具体的服务类提供服务,因为接口是不能实例化去提供服务的。就产生了“客户类不准实例化具体服务类”和“客户类需要具体服务类”这样一对矛盾。为了解决这个矛盾,开发人员提出了一种模式:客户类定义一个注入点,用于服务类的注入,而客户类的客户类负责根据情况,实例化服务类,注入到客户类中,从而解决了这个矛盾。
(客户类要使用具体的服务类,但是根据面向对象的原则客户类中不能实例化具体服务类,因此需要在客户端定义一种注入的方法,使之无需实例化即可调用具体服务类)
传统方法:客户类中实例化具体的服务类
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Origin
{
class Program
{
static void Main(string[] args)
{
Novel novel = new Novel();
novel.ByReading();
}
}
class Read
{
public void ToRead()
{
var tempBook = new Novel(); //问题所在——客户类实例化具体的服务类
tempBook.ByReading();
}
}
abstract class Book
{
public abstract void ByReading();
}
class Novel : Book
{
public override void ByReading()
{
Console.WriteLine("Novel");
}
}
}
2.定义:
依赖注入(Dependency Injection),是这样一个过程:由于某客户类只依赖于服务类的一个接口,而不依赖于具体服务类,所以客户类只定义一个注入点。在程序运行过程中,客户类不直接实例化具体服务类实例,而是客户类的运行上下文环境或专门组件负责实例化服务类,然后将其注入到客户类中,保证客户类的正常运行。
3.目的:解耦,降低耦合度
4.依赖注入实现方式:
(1)
构造函数注入:具体服务类在客户类之外已经实例化完毕,再将具体服务类的实例当作参数传入客户类的构造函数中,从而实现注入
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConstructorInjection
{
class Program
{
static void Main(string[] args)
{
Novel novel = new Novel();
Magazine magazine = new Magazine();
Read readNovel = new Read(novel);
Read readMagazine = new Read(magazine);
readNovel.ToRead();
readMagazine.ToRead();
}
}
class Read
{
private Book book;
public Read(Book _book)
{
this.book = _book;
}
public void ToRead()
{
book.ByReading();
}
}
abstract class Book
{
public abstract void ByReading();
}
class Novel : Book
{
public override void ByReading()
{
Console.WriteLine("You are reading Novel");
}
}
class Magazine : Book
{
public override void ByReading()
{
Console.WriteLine("You are reading Magazine");
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace SetterInjection
{
class Program
{
static void Main(string[] args)
{
Read read = new Read();
read.Book = new Novel();
read.ToRead();
read.Book = new Magazine();
read.ToRead();
}
}
class Read
{
private Book book;
public Book Book
{
get{ return book; }
set{ book = value; }
}
public void ToRead()
{
book.ByReading();
}
}
abstract class Book
{
public abstract void ByReading();
}
class Novel : Book
{
public override void ByReading()
{
Console.WriteLine("You are reading Novel");
}
}
class Magazine : Book
{
public override void ByReading()
{
Console.WriteLine("You are reading Magazine");
}
}
}
(3)接口注入:运用接口在客户类中实现注入具体服务类的函数
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace InterfaceInjection
{
class Program
{
static void Main(string[] args)
{
IBook novel = new Novel();
IBook magazine = new Magazine();
Read read = new Read();
read.Inject(novel);
read.ToRead();
read.Inject(magazine);
read.ToRead();
}
}
interface IRead
{
void Inject(IBook book);
}
class Read : IRead
{
IBook book;
public void Inject(IBook _book)
{
book = _book;
}
public void ToRead()
{
book.ByReading();
}
}
interface IBook
{
void ByReading();
}
class Novel : IBook
{
public void ByReading()
{
Console.WriteLine("You are reading Novel");
}
}
class Magazine : IBook
{
public void ByReading()
{
Console.WriteLine("You are reading Magazine");
}
}
}
参考资料:https://www.codeproject.com/Tips/657668/Dependency-Injection-DI