滾滾長江東逝水,浪花淘盡英雄。一代代的先輩的努力才造就我們的今天,細數歷史的進步會讓人深感受益良多。
本系列文將着重比對歷史的發展和控制反轉產生的關系,此文為引導文,主要介紹依賴注入,之后會有一系列文章來分析各種實現方式,希望大家拍磚。
[小九的學堂,致力於以平凡的語言描述不平凡的技術。如要轉載,請注明來源:小九的學堂。cnblogs.com/xfuture]
歷史的發展
遠古母系氏族,每個人都是一個獨立的個體,需要什么工具就需要自己去打磨一件工具,自己需要了解所有的流程才能生存。比如打獵,從前期准備繩索,尖木,到中期做陷阱,后期收成,都需要了解的非常透徹。對應編程中便是new 繩索(),new 尖木(),new 陷阱(),new X()。實例化所有需要的資源,然后再進行邏輯流程。
人類逐漸在進步,工業革命的來襲,改變了整個社會的結構。人再不需要了解所有的流程,只需要去一個工廠或者采購平台,輸入自己想要的東西,便能得到。對應編程中便是工廠模式,需要一個靜態工廠類,一個抽象產品類型的類,一個你想拿到的可以具象化的產品類,從此便進入了全民淘寶年代,需要什么購買什么。
當你為了修一個頂樓的燈泡購買了梯子,但當修好后,如何處理這個梯子便成了難題,扔掉不舍,不扔去賣二手又很麻煩。這時候就需要我們的主角:和諧社會登場了!主張不鋪張不浪費,這便是一種回收機制,你需要它只需要說一聲,秒秒鍾就到你手里,你也不需要知道他來自哪里。不需要了你也不用管,我直接秒秒鍾再變走。是不是有一種魔術的感覺?這便是依賴注入!依賴注入解除了對象和對象的依賴關系,需要其他對象時候,會有外部直接注入給你,而你不需要。對象符合OCP原則(對外擴展開放,對修改關閉), 容器負責所有關系匹配。在此層,容器便是這個社會的規則,而對象只需要關心自己所完成的一部分就好。輕松愜意!
依賴注入:Dependency Injection
從起始的new,new,new到后來的多態,面向接口編程,匹配協議規定的規則,直到按需分配,外部注入的控制反轉依賴注入。實際上就和人類進步的邏輯是一樣的,目的就是為了讓工作分配的更明確,更效率,彼此依賴越來越少。依賴注入隔離了變化,讓之不會影響不變的對象部分。依賴注入實際上是很多原則的合體。多態使類不再依賴其他服務類,只需要接口,實現了OCP(對外擴展開放,對修改關閉)。為了不需要實例具體的服務類,就需要定義注入點(接口),容器來進行服務,實現注入。
注入容器:Container
依賴注入需要一個容器來儲存所有的資源,根據你的需要按需分配,進行注入。依賴注入還有個名字叫控制反轉,就是大家經常說的IOC。
輕量級的有Unity Container, Autofac, Spring等,重量級有EJB, 還有游離在輕重之間的是JBoss等。之后系列文會詳細介紹幾種常用的,比如container,autofac,ejb。
由於本人經常使用prism,orchard,故而會更詳細介紹container和autofac,也會把使用心得更多分享給大家。
基本技術:反射
IOC是工廠模式的升華,最基本的技術是“反射”。根據一個注入的匹配表或者規則,來進行靈活的注入。
注入規則:
1. xml來進行配置。
Spring使用xml文件來進行beans的匹配。好處在於完全抽離了代碼層次,在xml進行配置,用字符串來進行反射注入。但壞處就是xml的維護,需要一個很好的IDE
2.Assembly注入,class,interface匹配。在.NET里個人比較喜歡這種。
var builder = new ContainerBuilder(); builder.RegisterGeneric(typeof(Dal<>)).As(typeof(Idal<>)).InstancePerDependency(); builder.RegisterGeneric(typeof(Repository<>)).As(typeof(IRepository<>)).InstancePerDependency(); builder.Register(c=>new PersionBll((IRepository<Persion>).Resolve(typeof(IRepository<Persion>)))); builder.Register(c => new CustomBll((IRepository<Custom>) c.Resolve(typeof(IRepository<Custom>)))); var container = builder.Build()
這里只大概列出一些例子。具體會有詳細介紹在系列篇后篇。
注入方法:
1.接口注入,2.構造函數注入,3.屬性注入
開碟小菜(不使用容器,僅使用接口和實現類來展現依賴注入的基本邏輯)
場景:家里很多電視,有時候這個可以用,有時候那個可以用。希望能在替換的時候,個人這邊是不需要更改什么的,依然是拿起遙控器就能看電視,不管是哪個。
解決方案:(接口注入)
// 創建實現看電視功能的接口 public interface ITvProvider { void WatchTv(); } // 創建一個TV的實體類,繼承ITvProvider,實現其WatchTv方法。 public class KonkaTv:ITvProvider { public void WatchTv() { // 實現看康佳電視功能的邏輯代碼 } } // 創建一個注入用的接口,實現類似容器/XML鏈接對象匹配的功能 public interface ITvInjecter { void InjectTv(ITvProvider tvProvider); } // 創建一個看電視的控件,繼承ITvInjecter(容器時則是繼承類似IDepency這種可以拿到容器, 這里是不使用容器的方法) public Control WatchTvControl:ITvInjecter { private ITvProvider _tvProvider; // 若使用容器,則在構造函數里既可以實現注入,不用手工來寫注入方法。 public void InjectTv(ITvProvider tvProvider) { _tvProvider = tvProvider } public WatchTvControl() { // 注入完成后便可以使用其watchtv方法 _tvProvider.WatchTv(); } } // 主程序,代碼層次實現注入並調用 public partial class App { private void Application_Startup(object sender, StartupEventArgs e) { ITvProvider tvProvider = new KonkaTv(); WatchTvControl watchTvControl = new WatchTvControl(); watchTvControl.InjectTv(tvProvider); } }
通過這樣的調用,就可是實現解耦和。當你想要更換Tv的時候只需要在主程序中更換就好,其余功能模塊則完全不需要更改。(容器則是注入其他Tv實體類就好)
希望大家點贊關注和拍磚。個人是在做.net,比較擅長使用prism和orchard(非常宏大的設計模式集合的CMS框架,分布式網絡的福音),對依賴注入的好處感受也比較深刻一些.總之希望大家持續關注。我也會努力提升自己來寫出更好文章豐富這個小學堂的,希望每項技術都能映射到現實的例子,其實編程就是人生啊!
