DIP 依赖倒置原则: 系统架构时, 高层模块不应该依赖于低层模块, 二者通过抽象来依赖
依赖抽象, 而不是细节
贯彻依赖倒置原则, 左边能抽象, 右边实例化的时候不能直接用抽象, 所以需要借助一个第三方
高层本来是依赖低层, 但是可以通过工厂 (容器) 来决定细节, 去掉了对低层的依赖
IoC 控制反转: 把高层对低层的依赖, 转移到第三方决定, 避免高层对低层的直接依赖(是一种目的)
那么程序架构就具备良好扩展性和稳定性
DI 依赖注入: 是用来实现 IoC 的一种手段,
在构造对象时, 可以自动的去初始化, 对象需要的对象
构造函数注入 属性注入 方法注入, IoC 容器初始化 ApplePhone 的时候 通过配置文件实例化 属性, 方法, 构造函数
- using Microsoft.Practices.Unity;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- using System.Threading.Tasks;
- using Ruanmou.Interface;
- using System;
- using Unity.Attributes;
- namespace Ruanmou.Service
- {
- public class ApplePhone : iPhone
- {
- [Dependency]// 属性注入: 不错, 但是有对容器的依赖
- public IMicrophone iMicrophone { get; set; }
- public IHeadphone iHeadphone { get; set; }
- public IPower iPower { get; set; }
- //[InjectionConstructor]
- public ApplePhone()
- {
- Console.WriteLine("{0}构造函数", this.GetType().Name);
- }
- //[InjectionConstructor]// 构造函数注入: 最好的, 默认找参数最多的构造函数
- public ApplePhone(IHeadphone headphone)
- {
- this.iHeadphone = headphone;
- Console.WriteLine("{0}带参数构造函数", this.GetType().Name);
- }
- public void Call()
- {
- Console.WriteLine("{0}打电话", this.GetType().Name);
- }
- [InjectionMethod]// 方法注入: 最不好的, 增加一个没有意义的方法, 破坏封装
- public void Init1234(IPower power)
- {
- this.iPower = power;
- }
- }
- }
不管是构造对象, 还是注入对象, 这里都是靠反射做到的
有了依赖注入, 才可能做到无限层级的依赖抽象, 才能做到控制反转
IoC Unity 容器 可以通过代码注册或配置文件注册接口对应实现类, 实现了不依赖具体, 可以对对象全局单例, 线程单例
例子 1
Service 业务逻辑层升级, 在原有 1.0 的基础上添加一些功能, 使用配置文件注册
- <container name="testContainer1">
- <register type="Ruanmou.Interface.iPhone,Ruanmou.Interface" mapTo="Ruanmou.Service.ApplePhone, Ruanmou.Service"/>
- <register type="Ruanmou.Interface.iPhone,Ruanmou.Interface" mapTo="Ruanmou.Service.AndroidPhone, Ruanmou.Service" name="Android"/>
- <register type="Ruanmou.Interface.IMicrophone, Ruanmou.Interface" mapTo="Ruanmou.Service.Microphone, Ruanmou.Service"/>
- <register type="Ruanmou.Interface.IHeadphone, Ruanmou.Interface" mapTo="Ruanmou.Service.Headphone, Ruanmou.Service"/>
- <register type="Ruanmou.Interface.IPower, Ruanmou.Interface" mapTo="Ruanmou.Service.Power, Ruanmou.Service"/>
- <register type="Ruanmou.IDAL.IBaseDAL, Ruanmou.IDAL" mapTo="Ruamou.DAL.BaseDAL, Ruamou.DAL"/>
- </container>
- <container name="testContainer">
- <register type="Ruanmou.Interface.iPhone,Ruanmou.Interface" mapTo="Ruanmou.Service.AndroidPhone, Ruanmou.Service.Extend"/>
- <register type="Ruanmou.Interface.iPhone,Ruanmou.Interface" mapTo="Ruanmou.Service.AndroidPhone, Ruanmou.Service.Extend" name="Android"/>
- <register type="Ruanmou.Interface.IMicrophone, Ruanmou.Interface" mapTo="Ruanmou.Service.Microphone, Ruanmou.Service.Extend"/>
- <register type="Ruanmou.Interface.IHeadphone, Ruanmou.Interface" mapTo="Ruanmou.Service.Headphone, Ruanmou.Service.Extend"/>
- <register type="Ruanmou.Interface.IPower, Ruanmou.Interface" mapTo="Ruanmou.Service.Power, Ruanmou.Service.Extend"/>
- <register type="Ruanmou.IDAL.IBaseDAL, Ruanmou.IDAL" mapTo="Ruamou.DAL.BaseDAL, Ruamou.DAL"/>
- </container>
只需要把服务 2.0 的类库(实现 1.0 的原有接口)dll 拿过来即可使用, 代码不做任何修改
例子 2 业务扩展, 新加功能
应该是加几个接口和实现类的映射, 就可以解决了.
例子 3 实现 AOP
方法需要加日志, 加异常管理, 可以不修改原有代码, 直接新加异常管理类等的类库, 在 Unity 配置文件添加 AOP 配置节点即可实现
配置文件配置,
- <container name="testContainerAOP">
- <extension type="Interception"/>
- <register type="Ruanmou.Interface.iPhone,Ruanmou.Interface" mapTo="Ruanmou.Service.AndroidPhone, Ruanmou.Service.Extend">
- <interceptor type="InterfaceInterceptor"/>
- <interceptionBehavior type="Ruanmou.Framework.AOP.AuthorizeBehavior, Ruanmou.Framework"/>
- <interceptionBehavior type="Ruanmou.Framework.AOP.SmsBehavior, Ruanmou.Framework"/>
- <interceptionBehavior type="Ruanmou.Framework.AOP.ExceptionLoggingBehavior, Ruanmou.Framework"/>
- <interceptionBehavior type="Ruanmou.Framework.AOP.CachingBehavior, Ruanmou.Framework"/>
- <interceptionBehavior type="Ruanmou.Framework.AOP.LogBeforeBehavior, Ruanmou.Framework"/>
- <interceptionBehavior type="Ruanmou.Framework.AOP.ParameterCheckBehavior, Ruanmou.Framework"/>
- <interceptionBehavior type="Ruanmou.Framework.AOP.LogAfterBehavior, Ruanmou.Framework"/>
- </register>
- <register type="Ruanmou.Interface.iPhone,Ruanmou.Interface" mapTo="Ruanmou.Service.AndroidPhone, Ruanmou.Service.Extend" name="Android"/>
- <register type="Ruanmou.Interface.IMicrophone, Ruanmou.Interface" mapTo="Ruanmou.Service.Microphone, Ruanmou.Service.Extend"/>
- <register type="Ruanmou.Interface.IHeadphone, Ruanmou.Interface" mapTo="Ruanmou.Service.Headphone, Ruanmou.Service.Extend"/>
- <register type="Ruanmou.Interface.IPower, Ruanmou.Interface" mapTo="Ruanmou.Service.Power, Ruanmou.Service.Extend"/>
- <register type="Ruanmou.IDAL.IBaseDAL, Ruanmou.IDAL" mapTo="Ruamou.DAL.BaseDAL, Ruamou.DAL">
- </register>
- </container>
贴一个异常处理的 AOP 例子代码
- namespace Ruanmou.Framework.AOP
- {
- public class ExceptionLoggingBehavior : IInterceptionBehavior
- {
- public IEnumerable<Type> GetRequiredInterfaces()
- {
- return Type.EmptyTypes;
- }
- public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext)
- {
- IMethodReturn methodReturn = getNext()(input, getNext);
- Console.WriteLine("ExceptionLoggingBehavior");
- if (methodReturn.Exception == null)
- {
- Console.WriteLine("无异常");
- }
- else
- {
- Console.WriteLine($"异常:{methodReturn.Exception.Message}");
- }
- return methodReturn;
- }
- public bool WillExecute
- {
- get { return true; }
- }
- }
- }
例子 4 数据访问层的替换, 因为已经不依赖具体实现, 把配置文件的接口对应的数据访问层实现类替换即可, 配置文件格式为 InterFace Map 实现类
数据访问层的封装公共增删改查, Unity 管理 EF DBcontext, 保持全局或线程单例还没有看到, 最近在学内存管理和. Net 垃圾回收
来源: https://www.cnblogs.com/kongsq/p/9751716.html