场景举例:我们使用手机打电话的时候,我记不住电话号码,所以需要先打开电话本,因为手机没有电了,所以需要再给手机充上电,我习惯戴上耳机打电话,所以最后要戴上耳机打电话
也就是说在这个场景下:构造手机对象的时候,手机对象依赖于电话本对象,同时依赖于充电器对象,同时也依赖于耳机对象。
- 接口
1、手机接口
手机接口,里面有两个方法,一个是打电话,一个是其他方式打电话
namespace David.General.EF.Bussiness.Interface { public interface IPhoneService { ////// 打电话 /// void Call(); /// /// 其他方式打电话 /// /// void OtherCall(IEarphoneService iEarphoneService); } }
2、电话本接口
电话本接口,里面有一个打开电话本方法
namespace David.General.EF.Bussiness.Interface { public interface IPhoneBookService { ////// 打开电话本 /// void Open(); } }
3、电源接口
电源接口,里面有一个充电方法
namespace David.General.EF.Bussiness.Interface { public interface IPowerService { ////// 充电 /// void ChargeBattery(); } }
4、耳机接口
耳机接口,里面有一个戴上耳机方法
namespace David.General.EF.Bussiness.Interface { public interface IEarphoneService { ////// 戴上耳机 /// void PutOn(); } }
- 实现
1、手机接口实现
namespace David.General.EF.Bussiness.Service { public class ApplePhoneService : IPhoneService { public IPowerService IPowerService { get; set; } [Dependency]//属性注入 public IPhoneBookService IPhoneBookService { get; set; } public ApplePhoneService(IPowerService iPowerService) { IPowerService = iPowerService; } ////// 打电话 /// public void Call() { IPhoneBookService.Open(); IPowerService.ChargeBattery(); Console.WriteLine($"{nameof(ApplePhoneService)}打电话"); } //方法注入 [InjectionMethod] public void OtherCall(IEarphoneService earphoneService) { IPhoneBookService.Open(); IPowerService.ChargeBattery(); earphoneService.PutOn(); Console.WriteLine($"{nameof(ApplePhoneService)}打电话"); } } }
2、电话本接口实现
namespace David.General.EF.Bussiness.Service { public class PhoneBookService : IPhoneBookService { ////// 打开电话本 /// public void Open() { Console.WriteLine($"{nameof(PhoneBookService)}打开电话本"); } } }
3、电源接口实现
namespace David.General.EF.Bussiness.Service { public class ApplePowerService : IPowerService { ////// 充电 /// public void ChargeBattery() { Console.WriteLine($"{nameof(ApplePowerService)}充电"); } } }
4、耳机接口实现
namespace David.General.EF.Bussiness.Service { public class EarphoneService : IEarphoneService { ////// 戴上耳机 /// public void PutOn() { Console.WriteLine($"{nameof(EarphoneService)}戴上耳机"); } } }
- 调用
namespace David.General.EF.Test.IOCTest { public class UnityTest { public static void Show() { //1、实例化容器 IUnityContainer container = new UnityContainer();// //2、注册类型,但凡要用的类型,都需要注册,否则容器怎么工作呢 container.RegisterType(); container.RegisterType (); container.RegisterType (); container.RegisterType (); //3、获取实例 IPhoneService iPhone = container.Resolve (); } } }
- 效果图
1、在构造ApplePhoneService的时候,先去构造了ApplePowerService,也就是先构造了电源对象
2、在构造完ApplePhoneService后,又紧跟着构造了PhoneBookService,也就是构造了电话本对象,因为构造顺序是构造函数注入--属性注入--方法注入
3、在构造完PhoneBookService后,最后构造了EarphoneService,我们在调用的时候没有主动去调用OtherCall方法,但是因为OtherCall标记了InjectionMethod特性,所以会注入方法的依赖对象,也就同时会调用该方法
- 总结
注册类型的时候:没有抽象实现不行,没有父子关系不行,但凡要用的类型,都需要注册,否则容器怎么工作呢
为什么要标记特性:因为那么多属性,那么多构造函数,容器怎么知道要构造哪一个呢,所以需要特性标记一下
构造函数比较特殊:特殊在就算没有标记特性,容器默认构造找参数最多的构造函数,可以不用特性,不用特性意味着可以去掉对容器的依赖