<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      DIP原則、IoC以及DI

      一、DIP原則

      • 高層模塊不應該依賴于底層模塊,二者都應該依賴于抽象。
      • 抽象不應該依賴于細節,細節應該依賴于抽象。

      該原則理解起來稍微有點抽象,我們可以將該原則通俗的理解為:"依賴于抽象”

      該規則告訴我們,程序中所有的依賴關系都應該終止于抽象類或者接口,從而達到松耦合的目的。因為我們在應用程序中編寫的大多數具體類都是不穩定的。我們不想直接依賴于這些不穩定的具體類。通過把它們隱藏在抽象和接口的后面,可以隔離它們的不穩定性。

      舉個例子

      一個Button對象會觸發Click方法,當被按下時,會調用Light對象的TurnOn方法,否則會調用Light對象的TurnOff方法。

      這個設計存在兩個問題:

      1. Button類直接依賴于Light類,這種依賴關系意味著當Light改變時,Button類會受到影響;
      2. Button對象只能控制Light對象,想要控制電視或者冰箱就不行了;

      新的設計:

      這個方案對那些需要被Button控制的對象提出了一個約束。需要被Button控制的對象必須要實現ISwitchableDevice接口。

      所為原則,只是描述了什么是對的,但是并沒有說清楚如何去做。在軟件工程中,我們經常使用DI(依賴注入)來達到這個目的。但是提到依賴注入,人們又會經常提起IoC這個術語。所以先讓我們來了解下什么是IoC。

      二、IoC

      IoC的全名是Inverse of Control,即控制反轉。這一術語并不是用來描述面向對象的某種原則或者模式,IoC體現為一種流程控制的反轉,一般用來對框架進行設計。

      舉個例子

      ReportService是一個用來顯示報表的流程,該流程包括Trim()Clean()Show()三個環節。

      public class ReportService
      {
          private string _data;
      
          public ReportService(string data)
          {
              _data = data;
          }
      
          public void Trim(string data)
          {
              _data = data.Trim();
          }
      
          public void Clean()
          {
              _data = _data.Replace("@", "");
              _data = _data.Replace("-", "");
      
              //...other rules
          }
      
          public void Show()
          {
              Console.WriteLine(_data);
          }
      
      }
      

      客戶端通過下面的方式使用該服務:

      var reportService = new ReportService(input);
      reportService.Trim(input);
      reportService.Clean();
      reportService.Show();
      

      這樣的一個設計體現了過程式的思考方式,客戶端依次調用每個環節從而組成了整個報表顯示流程,這樣的代碼體現了:客戶端擁有流程控制權

      我們來分析下這段代碼,ReportService提供了3個可重用的Api,正如ReportService的命名一樣,它告訴我們它是一個服務,我們只能重用他提供的三個服務,它無法提供一個打印報表的流程,整個流程是客戶端來控制的。

      另外,該設計也違反了tell, Don't ask原則

      打印報表作為一個可復用的流程,不但可以提供可復用的流程環節,還可以提供可復用的流程的定義,當我們進行框架設計的時候,往往會將整個流程控制定制在框架之中,然后提供擴展點供客戶端定制。這樣的思想體現了流程的所有權從客戶端到框架的反轉。

      比如asp.net mvc或者asp.net api框架,內部定義了http消息從請求,model binder,controller的激活,action的執行,返回response
      等可復用的流程。同時還提供了每一個環節的可擴展點。

      利用以上思想,我們對ReportService重新設計。

      新的設計

      采用IoC思想重新設計該報表服務,將原來客戶端擁有的流程控制權反轉在報表服務框架中ReportService這樣的命名已經不適合我們的想法,新的實現不但提供了報表打印的相關服務,同時還提供了一個可復用的流程,因此重新命名為ReportEngine。我們可以通過模板方法達到此目的:

      public class ReportEngine
      {
          private  string _data;
      
          public ReportEngine(string data)
          {
              _data = data;
          }
      
          public void Show()
          {
              Trim();
              Clean();
              Display();
          }
      
          public virtual void Trim()
          {
              _data = _data.Trim();
          }
      
          public virtual void Clean()
          {
              _data = _data.Replace("@", "");
              _data = _data.Replace("-", "");
          }
      
          public virtual void Display()
          {
              Console.WriteLine(_data);
          }
      
      }
      

      此時的報表服務在Show()方法中定義好了一組可復用的流程,客戶端只需要根據自己的需求重寫每個環節即可。客戶端可以通過下面的方式使用ReportEngine

      var reportEngine=new StringReportEngine(input);
      reportEngine.Show();
      

      三、DI(Dependency Injection)

      DI即依賴注入,主要解決了2個問題:

      1. 松耦合,由DI容器來創建對象,符合DIP原則;
      2. 符合IoC的思想,整個應用程序事先定義好了一套可工作的流程,通過在客戶端替換DI容器中的具體實現達到重寫某個組件的目的;

      除此之外,使用依賴注入還可以帶來以下好處:

      • 促使你寫出更加符合面向對象原則的代碼,符合優先使用對象組合,而不是繼承的原則;
      • 使系統更加具有可測試性;
      • 使系統更加具備可擴展性和可維護性;
      • 由于所有組件都由DI容器管理,所以可以很方便的實現AOP攔截

      我記得之前在stackoverflow上看到過類似這樣的一個問題:

      如何給5歲小孩解釋什么叫DI?

      得分最高的答案是:小孩在餓的時候只需喊一聲我要吃飯即可,而無需關注吃什么飯是怎么來的等問題。

       public class Kid
       {
          private readonly IFoodSupplier _foodSupplier;
      
          public Kid(IFoodSupplier foodSupplier)
          {
              _foodSupplier = foodSupplier;
          }
      
          public void HaveAMeal()
          {
              var food = _foodSupplier.GetFood();
              //eat
          }
      }
      

      DI的背后是一個DI Container(DI容器)在發揮作用。DI之所以能夠工作需要兩個步驟:

      1. 將組件注冊到DI容器中;
      2. DI容器統一管理所有依賴關系,將依賴組件注入到所需要相應的組件中;

      3.1 組件的注冊方式

      組件注冊到DI容器中有3種方式:

      1. 通過XML文件注冊
      2. 通過Attribute(Annotation)注冊
      3. 通過DI容器提供的API注冊

      .net平臺中的大多數DI框架都通過第三種方式進行組件注冊,為了介紹這3種不同的注冊方式,我們通過Java平臺下的Spring框架簡單介紹:Java中的Spring最早以XML文件的方式進行組件注冊,發展到目前主要通過Annotation來注冊。
      假如我們有CustomerRepository接口和相應的實現CustomerRepositoryImpl,下面用三種不同的方式將CustomerRepositoryCustomerRepositoryImpl的對應關系注冊在DI容器中:

      public interface CustomerRepository {
          List<Customer> findAll();
      }
      
      public class CustomerRepositoryImpl implements CustomerRepository {
          public List<Customer> findAll() {
              List<Customer> customers = new ArrayList<Customer>();
              Customer customer = new Customer("Bryan","Hansen");
      
              customers.add(customer);
              return customers;
          }
      }
      

      3.1.1、xml文件注冊

      <bean name="customerRepository" class="com.thoughtworks.xml.repository.CustomerRepositoryImpl"/>
      

      3.1.2、Annotation注冊

      @Repository("customerRepository")
      public class CustomerRepositoryImpl implements CustomerRepository {
          public List<Customer> findAll() {
             //...
          }
      }
      

      3.1.3、通過Java代碼來實現注冊

      @Configuration
      public class AppConfig {
          @Bean(name = "customerRepository")
          public CustomerRepository getCustomerRepository() {
              return new CustomerRepositoryImpl();
          }
      }
      

      3.1.4通過下面的方式從Container來獲取一個實例

      appContext.getBean("customerService", CustomerService.class);
      

      一旦我們將所有組件都注冊在容器中,就可以靠DI容器進行依賴注入了。

      3.2 依賴注入的三種方式

      3.2.1. 構造器注入

      正如上面Kid的實現一樣,我們通過構造器來注入IFoodSupplier組件,這種方式也是依賴注入最佳方式。

      3.2.2. 屬性注入

      public class Kid2
      {
          public IFoodSupplier FoodSupplier { get; set; }
      
          public void HaveAMeal()
          {
              var food = FoodSupplier.GetFood();
              //eat
          }
      }
      

      即通過一個可讀寫的屬性完成注入,該方案的缺點在于為了達到依賴注入的目的而破壞了對象的封裝性,所以不推薦。

      3.2.3 方法注入

      通過添加方法的參數來完成注入,一般來說這種方式都可以通過構造器注入的方式來替換,所以也不太常用。值得一提的是asp.net core源碼中用到了這種注入方式。

      四、依賴注入實例

      1、Register Resolve Release Pattern

      下面描述了一個很簡單的Console application, 所有的組件都通過Castle Windsor容器進行構造器注入:

      //register
      var  container = new WindsorContainer();
      container.Register(Component.For<IParser>().ImplementedBy<Parser>());
      container.Register(Component.For<IWriter>().ImplementedBy<Writer>());
      container.Register(Component.For<Application>());
      
      //resolve
      var application = container.Resolve<Application>();
      application.Execute("hel--lo, wor--ld");
      
      //release
      container.Release(application);
      

      這個例子向我們展示了一個最簡單的依賴注入使用方式,register所有組件,resolve客戶端程序,最后的release步驟向我們展示了如果顯示從DI容器得到一個對象,應該顯示釋放該組件。這一步在大多數情況下并不是必須的,但是在特定場景下會發生內存泄漏

      2、.net平臺下依賴注入最佳實踐

      下面的解決方案描述了一個典型的應用程序分層結構,該分層結構用來描述如何使用Catle windsor進行依賴注入,注意:這并不是一個合理的領域驅動案例,例如我將Domain模型引用到了Application或者ApplicationService程序集中。
      bestPractice
      處在項目最底層的Repository程序集定義了一組UserRepository及其接口IUserRepository,這樣的一個組件如何注冊在Windsor Container中呢?Castle提供了一種叫做WindsorInstaller的機制:

      public class RepositoryInstaller:IWindsorInstaller
      {
          public void Install(IWindsorContainer container, IConfigurationStore store)
          {
              container.Register(Component.For<IUserRepository>().ImplementedBy<UserRepository>().LifestyleScoped());
          }
      }
      

      該Installer利用Fluent Api定義了IUserRepositoryUserRepository的對應關系,相對于Java中的Spring框架提供的代碼注冊方式,該方案的優越之處是顯而易見的。
      另外的重點在于該Installer此時并沒有執行,只有當客戶端調用此Installer時,該組件才真真注冊進容器。這一點很關鍵,我們后面還會提到。

      接下來的ApplicationService層使用了Repository的抽象,一個典型的使用片斷如下:

      public class UserApplicationService : IUserApplicationService
      {
          private readonly IUserRepository _userRepository;
      
          public UserApplicationService(IUserRepository userRepository)
          {
              _userRepository = userRepository;
          }
      
          public void Register(User user)
          {
              _userRepository.Save(user);
          }
          //.....
      } 
      

      我們通過構造器注入的方式注入了IUserRepository,同時,作為Service層,它也擁有自己的Installer:

      public class ApplicationServiceInstaller:IWindsorInstaller
      {
          public void Install(IWindsorContainer container, IConfigurationStore store)
          {
              container.Register(
                  Classes.FromThisAssembly().BasedOn<IApplicationService>().WithServiceDefaultInterfaces().LifestyleScoped());
          }
      }
      

      上面的例子示范了如何通過Castle提供的高級api來實現將該程序集中所有繼承于IApplicationService的組件和其默認接口一次性全部注冊到DI容器中。
      比如UserApplicationServiceIUserApplicationService,以及未來將要實現的OrderApplicationService以及IOrderApplicationService

      接下來到客戶端程序集Application層,Application作為使用ApplicationService程序集的客戶端,他才擁有將組件注冊進DI容器的能力,我們定義一個ApplicationBootstrap來初始化DI容器并注冊組件:

      public class ApplicationBootstrap
      {
          public static IWindsorContainer Container { get; private set; }
      
          public static IWindsorContainer  RegisterComponents()
          {
              Container=new WindsorContainer();
      
              Container.Install(FromAssembly.This());
              Container.Install(FromAssembly.Containing<ApplicationServiceInstaller>());
              Container.Install(FromAssembly.Containing<RepositoryInstaller>());
      
      
              return Container;
          }
      }
      

      注意Container.Install(...)方法將執行不同應用程序的Installer,此時組件才真真注冊進DI容器。該實例展示了如何正確的使用依賴注入框架:

      1. 不同的程序集之間通過接口依賴,符合DIP原則;
      2. 通過依賴注入的方式定義好了可運行的流程,但是客戶端可以注冊不同的組件到DI容器中,符合IoC的思想;

      3、如何在asp.net mvc和asp.net webapi使用依賴注入

      本文提供的源碼中所含的WebApplicationSample項目演示了如何通過自定義WindsorControllerFactory來實現mvc的依賴注入,通過自定義WindsorCompositionRoot實現web api的依賴注入。

      五、高級進階

      asp.net core實現了一個還算簡單的DI容器DenpendencyInjection,感興趣的同學可以閱讀其源碼。

      六、源碼下載

      本文所描述的案例提供下載,點擊下載

      posted @ 2016-11-14 21:58  richiezhang  閱讀(3854)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 亚洲欧美牲交| 日韩精品亚洲专在线电影| 少妇人妻av毛片在线看| 亚洲精品一品区二品区三品区| 伊人激情av一区二区三区| 最新国产精品好看的精品| 4hu亚洲人成人无码网www电影首页| 久草热久草热线频97精品| 国产精品美女免费无遮挡| 欧美肥老太wbwbwbb | 人妻中文字幕一区二区视频| 免费人成在线观看网站| 日本乱码在线看亚洲乱码| 亚洲精品在线少妇内射| 野花香视频在线观看免费高清版 | av中文无码韩国亚洲色偷偷| 激情内射亚洲一区二区三区| 国产精品三级中文字幕| 国产精品无码a∨麻豆| 果冻传媒色av国产在线播放| 亚洲日韩精品无码一区二区三区| 中国大陆高清aⅴ毛片| 亚洲自拍偷拍中文字幕色| 丰满无码人妻热妇无码区| 金门县| 国产成人综合网在线观看| 亚洲av无码精品色午夜蛋壳| 欧美精欧美乱码一二三四区| 久久9精品区-无套内射无码| 日韩精品一区二区三区中文无码 | 亚洲这里只有久热精品伊人| 成人国产精品日本在线观看| 久久精品国产亚洲av天海翼| 国产成人理论在线视频观看| 正在播放国产对白孕妇作爱| 丰满妇女强制高潮18xxxx| 亚洲欧洲国产综合一区二区| 久久综合激情网| 国产精品午夜福利小视频| 亚洲精品一区二区制服| 婷婷久久综合九色综合88|