1.依賴倒置原則:(DIP)高層子產品不應依賴底層子產品,兩者都應依賴抽象。
為什麼依賴注入? 為了實作控制反轉.
為什麼控制反轉? 我們的軟體設計需要符合依賴倒置原則.
2.依賴注入(DI) 控制反轉(IOC)(技術手段)
·IOC容器,依賴注入,IOC控制反轉的關系
依賴注入,反轉依賴的!因為有了依賴注入,才有了控制反轉;
即先有容器再有依賴注入,最後才有控制反轉。
IOC容器,依賴注入架構的東西提供的。映射依賴、管理對象建立和生命周期;再也不用New,有人幫你new。
場景例子:假設你是一個五歲的小孩,你餓了就要吃,需求。怎麼找吃的?
1.找吃的 直接從冰箱拿
2.找媽媽要 父母(IOC容器)會給你做食物,然後拿給你(注入)
從你想吃東西的需求,從主動去冰箱(正轉)拿食物,到想吃的食物而被動獲得(反轉),即媽媽做
控制反轉:元件對象控制權的轉移。類型A(小孩)中需要使用類型B(食物),這個B的建立并不由A來負責,而是由第三方(媽媽)建立。
IOC一種反轉流、依賴和接口的方式,他把傳統上由程式代碼直接操控的對象的調用權交給第三方(容器),通過第三方來實作對象元件的配置和管理。
場景:父親給孩子講故事,隻要給父親一本書,他就可以照着書給孩子将故事。
1.不經過任何設計模式和設計原則加工的傳統的OOP方式,強依賴,以利于擴充。
namespace FatherStoryCustom
{
/// <summary>
/// 場景:父親給孩子講故事,隻要給父親一本書,他就可以照着書給孩子将故事。
///
/// 不經過任何設計模式和設計原則加工的傳統的OOP方式。。
/// </summary>
class Program
{
static void Main(string[] args)
{
Father father = new Father();
father.Read();
Console.ReadKey();
}
}
public class Book
{
public string GetContent()
{
return "從前有座山,山上有座廟.....";
}
}
public class Father
{
public void Read()
{
Book book = new Book();
Console.WriteLine("爸爸開始講故事啦..");
Console.WriteLine(book.GetContent());
}
}
}
場景:父親給孩子講故事,隻要給父親一本書,他就可以照着書給孩子将故事。
有一天需求變了,不給書了,給報紙,讀報紙上的新聞。
2.通過工廠模式來實作,但還是需要在工廠中建立對象
namespace FatherStoryDIP
{
/// <summary>
/// 場景:父親給孩子講故事,隻要給父親一本書,他就可以照着書給孩子将故事。
/// 有一天需求變了,不給書了,給報紙,讀報紙上的新聞。
/// 上一個普通做法耦合太強,父親太依賴書了。
/// </summary>
class Program
{
static void Main(string[] args)
{
// 工廠模式建立對象
Father father = new Father("Paper");
Console.ReadKey();
}
}
/// <summary>
/// 讀物的接口
/// </summary>
public interface IReader
{
string GetContent();
}
public class Paper : IReader
{
public string GetContent()
{
return "王思聰被限制消費..";
}
}
public class Book : IReader
{
public string GetContent()
{
return "從前有座山,山上有座廟...";
}
}
public class Father
{
private IReader _reader { get; set; }
// 工廠模式建立對象
public Father(string readerName)
{
_reader = ReaderFactory.GetReader(readerName);
}
public void Read()
{
Console.WriteLine("爸爸給孩子開始講故事了..");
Console.WriteLine(_reader.GetContent());
}
}
}
namespace FatherStoryDIP
{
public static class ReaderFactory
{
public static IReader GetReader(string readType)
{
if (string.IsNullOrEmpty(readType))
{
return null;
}
switch (readType)
{
case "Paper":
return new Paper();
case "Book":
return new Book();
default:
return null;
}
}
}
}
3.和上面2的場景一樣,通過依賴注入來建立對象。将上面2的代碼進行再更新。
工廠模式 =>更新=> IOC容器的基礎
IOC容器,一個自動化的工廠,還帶配送,要什麼給什麼。徹底的解耦,高層不依賴于低層,依賴抽象。
namespace FatherStoryDIP
{
/// <summary>
/// 場景:父親給孩子講故事,隻要給父親一本書,他就可以照着書給孩子将故事。
/// 有一天需求變了,不給書了,給報紙,讀報紙上的新聞。
/// </summary>
class Program
{
static void Main(string[] args)
{
// 通過容器建立對象
var sc = new ServiceCollection();
// 接口對應執行個體進行注冊
//sc.AddScoped(typeof(IReader), typeof(Book));
//var sp = sc.BuildServiceProvider();
//IReader reader = sp.GetService<IReader>();
//Father father = new Father(reader);
//father.Read();
// Unity建立容器 全程沒有new對象
var container = new UnityContainer();
container.RegisterType<IReader, Book>();
container.RegisterType<Father>();
// 解析容器中的對象,用什麼泛型中填什麼
var father = container.Resolve<Father>();
father.Read();
Console.ReadKey();
}
}
/// <summary>
/// 讀物的接口
/// </summary>
public interface IReader
{
string GetContent();
}
public class Paper : IReader
{
public string GetContent()
{
return "王思聰被限制消費..";
}
}
public class Book : IReader
{
public string GetContent()
{
return "從前有座山,山上有座廟...";
}
}
public class Father
{
private IReader _reader { get; set; }
public Father(IReader reader)
{
_reader = reader;
}
public void Read()
{
Console.WriteLine("爸爸給孩子開始講故事了..");
Console.WriteLine(_reader.GetContent());
}
}
}
容器類似于一個登記本,生産的東西登記到容器中,用的時候直接從容器中取。
目前代碼用寫死的方式注冊,注冊類型的方式有很多種
1.配置檔案,動态加載
2.批量注冊,将特殊辨別的實體類(例:字尾為Service或者有某個特性)的全部注冊到容器中
3.通過反射,掃描程式集,找到你想要找到的類注冊進來。例如字尾名為Service