做鞋的贸易公司网站怎么做好,京东网站建设吗,重庆綦江网站建设,wordpress导入汉化包一、DIP原则 高层模块不应该依赖于底层模块#xff0c;二者都应该依赖于抽象。抽象不应该依赖于细节#xff0c;细节应该依赖于抽象。 该原则理解起来稍微有点抽象#xff0c;我们可以将该原则通俗的理解为#xff1a;依赖于抽象”。 该规则告诉我们#xff0c;程序… 一、DIP原则 高层模块不应该依赖于底层模块二者都应该依赖于抽象。抽象不应该依赖于细节细节应该依赖于抽象。 该原则理解起来稍微有点抽象我们可以将该原则通俗的理解为依赖于抽象”。 该规则告诉我们程序中所有的依赖关系都应该终止于抽象类或者接口从而达到松耦合的目的。因为我们在应用程序中编写的大多数具体类都是不稳定的。我们不想直接依赖于这些不稳定的具体类。通过把它们隐藏在抽象和接口的后面可以隔离它们的不稳定性。 举个例子 一个Button对象会触发Click方法当被按下时会调用Light对象的TurnOn方法否则会调用Light对象的TurnOff方法。 这个设计存在两个问题 Button类直接依赖于Light类这种依赖关系意味着当Light改变时Button类会受到影响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, Dont ask原则。 打印报表作为一个可复用的流程不但可以提供可复用的流程环节还可以提供可复用的流程的定义当我们进行框架设计的时候往往会将整个流程控制定制在框架之中然后提供扩展点供客户端定制。这样的思想体现了流程的所有权从客户端到框架的反转。 比如asp.net mvc或者asp.net api框架内部定义了http消息从请求model bindercontroller的激活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 reportEnginenew StringReportEngine(input);
reportEngine.Show(); 三、DI(Dependency Injection) DI即依赖注入主要解决了2个问题 松耦合由DI容器来创建对象符合DIP原则符合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 ContainerDI容器)在发挥作用。DI之所以能够工作需要两个步骤 将组件注册到DI容器中;DI容器统一管理所有依赖关系将依赖组件注入到所需要相应的组件中; 3.1 组件的注册方式 组件注册到DI容器中有3种方式 通过XML文件注册通过Attribute(Annotation)注册通过DI容器提供的API注册 .net平台中的大多数DI框架都通过第三种方式进行组件注册为了介绍这3种不同的注册方式我们通过Java平台下的Spring框架简单介绍Java中的Spring最早以XML文件的方式进行组件注册发展到目前主要通过Annotation来注册。假如我们有CustomerRepository接口和相应的实现CustomerRepositoryImpl下面用三种不同的方式将CustomerRepository和CustomerRepositoryImpl的对应关系注册在DI容器中 public interface CustomerRepository { ListCustomer findAll();
} public class CustomerRepositoryImpl implements CustomerRepository { public ListCustomer findAll() { ListCustomer customers new ArrayListCustomer();Customer customer new Customer(Bryan,Hansen);customers.add(customer); return customers;}
} 3.1.1、xml文件注册 bean namecustomerRepository classcom.thoughtworks.xml.repository.CustomerRepositoryImpl/ 3.1.2、Annotation注册 Repository(customerRepository)public class CustomerRepositoryImpl implements CustomerRepository { public ListCustomer findAll() { //...}
} 3.1.3、通过Java代码来实现注册 Configurationpublic 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容器进行构造器注入 //registervar container new WindsorContainer();
container.Register(Component.ForIParser().ImplementedByParser());
container.Register(Component.ForIWriter().ImplementedByWriter());
container.Register(Component.ForApplication());//resolvevar application container.ResolveApplication();
application.Execute(hel--lo, wor--ld);//releasecontainer.Release(application); 这个例子向我们展示了一个最简单的依赖注入使用方式register所有组件resolve客户端程序最后的release步骤向我们展示了如果显示从DI容器得到一个对象应该显示释放该组件。这一步在大多数情况下并不是必须的但是在特定场景下会发生内存泄漏。 2、.net平台下依赖注入最佳实践 下面的解决方案描述了一个典型的应用程序分层结构该分层结构用来描述如何使用Catle windsor进行依赖注入注意这并不是一个合理的领域驱动案例例如我将Domain模型引用到了Application或者ApplicationService程序集中。处在项目最底层的Repository程序集定义了一组UserRepository及其接口IUserRepository这样的一个组件如何注册在Windsor Container中呢Castle提供了一种叫做WindsorInstaller的机制 public class RepositoryInstaller:IWindsorInstaller{ public void Install(IWindsorContainer container, IConfigurationStore store) {container.Register(Component.ForIUserRepository().ImplementedByUserRepository().LifestyleScoped());}
} 该Installer利用Fluent Api定义了IUserRepository和UserRepository的对应关系相对于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().BasedOnIApplicationService().WithServiceDefaultInterfaces().LifestyleScoped());}
} 上面的例子示范了如何通过Castle提供的高级api来实现将该程序集中所有继承于IApplicationService的组件和其默认接口一次性全部注册到DI容器中。比如UserApplicationService和IUserApplicationService以及未来将要实现的OrderApplicationService以及IOrderApplicationService。 接下来到客户端程序集Application层Application作为使用ApplicationService程序集的客户端他才拥有将组件注册进DI容器的能力我们定义一个ApplicationBootstrap来初始化DI容器并注册组件 public class ApplicationBootstrap{ public static IWindsorContainer Container { get; private set; } public static IWindsorContainer RegisterComponents() {Containernew WindsorContainer();Container.Install(FromAssembly.This());Container.Install(FromAssembly.ContainingApplicationServiceInstaller());Container.Install(FromAssembly.ContainingRepositoryInstaller()); return Container;}
} 注意Container.Install(...)方法将执行不同应用程序的Installer此时组件才真真注册进DI容器。该实例展示了如何正确的使用依赖注入框架 不同的程序集之间通过接口依赖符合DIP原则通过依赖注入的方式定义好了可运行的流程但是客户端可以注册不同的组件到DI容器中符合IoC的思想 3、如何在asp.net mvc和asp.net webapi使用依赖注入 本文提供的源码中所含的WebApplicationSample项目演示了如何通过自定义WindsorControllerFactory来实现mvc的依赖注入通过自定义WindsorCompositionRoot实现web api的依赖注入。 五、高级进阶 asp.net core实现了一个还算简单的DI容器DenpendencyInjection感兴趣的同学可以阅读其源码。 原文地址http://www.cnblogs.com/richieyang/p/6060160.html.NET社区新闻深度好文微信中搜索dotNET跨平台或扫描二维码关注