一.场景

我们使用手机打电话的时候,因为手机没有电了,所以需要先给手机充上电,我记不住电话号码,所以需要再打开电话本,我习惯戴上耳机打电话,所以最后要戴上耳机打电话。
也就是说在这个场景下:构造手机对象的时候,手机对象依赖于充电器对象,同时依赖电话本对象,同时也依赖于耳机对象

二.接口

2.1.手机接口

手机接口,里面有两个方法,一个是打电话,一个是戴上耳机打电话

namespace UnityUse.Interface
{
    public interface IPhoneService
    {
        /// <summary>
        /// 打电话
        /// </summary>
        void Call();

        /// <summary>
        /// 带上耳机打电话
        /// </summary>
        /// <param name="iEarphoneService"></param>
        void EarphoneCall(IEarphoneService iEarphoneService);
    }
}

2.2.电源接口

电源接口,里面有一个充电方法

namespace UnityUse.Interface
{
    public interface IPowerService
    {
        /// <summary>
        /// 充电
        /// </summary>
        void ChargeBattery();
    }
}

2.3.电话本接口

电话本接口,里面有一个打开电话本方法

namespace UnityUse.Interface
{
    public interface IPhoneBookService
    {
        /// <summary>
        /// 打开电话本
        /// </summary>
        void Open();
    }
}

2.4.耳机接口
耳机接口,里面有一个戴上耳机方法

namespace UnityUse.Interface
{
    public interface IEarphoneService
    {
        /// <summary>
        /// 戴上耳机
        /// </summary>
        void PutOn();
    }
}

 三.实现

3.1.手机接口实现

namespace UnityUse.Service
{
    public class ApplePhoneService : IPhoneService
    {
        public IPowerService IPowerService { get; set; }

        /// <summary>
        /// 属性注入电话本服务
        /// </summary>
        [Dependency]
        public IPhoneBookService IPhoneBookService { get; set; }

        /// <summary>
        /// 构造函数注入电源服务
        /// </summary>
        /// <param name="iPowerService"></param>
        public ApplePhoneService(IPowerService iPowerService)
        {
            IPowerService = iPowerService;
        }

        /// <summary>
        /// 打电话
        /// </summary>
        public void Call()
        {
            Console.WriteLine($"*****************普通方式打电话开始*****************");
            IPowerService.ChargeBattery();
            IPhoneBookService.Open();
            Console.WriteLine($"{nameof(ApplePhoneService)}打电话");
            Console.WriteLine($"*****************普通方式打电话结束*****************");
        }

        /// <summary>
        /// 带上耳机打电话
        /// 方法注入耳机服务
        /// </summary>
        /// <param name="earphoneService"></param>
        [InjectionMethod]
        public void EarphoneCall(IEarphoneService iEarphoneService)
        {
            Console.WriteLine($"*****************带上耳机打电话打电话开始*****************");
            IPowerService.ChargeBattery();
            IPhoneBookService.Open();
            iEarphoneService.PutOn();
            Console.WriteLine($"{nameof(ApplePhoneService)}打电话");
            Console.WriteLine($"*****************带上耳机打电话打电话结束*****************");
        }
    }
}

3.2.电源接口实现

namespace UnityUse.Service
{
    public class ApplePowerService : IPowerService
    {
        /// <summary>
        /// 电源服务构造函数
        /// </summary>
        public ApplePowerService()
        {
            Console.WriteLine($"{nameof(ApplePowerService)}构造");
        }

        /// <summary>
        /// 充电
        /// </summary>
        public void ChargeBattery()
        {
            Console.WriteLine($"{nameof(ApplePowerService)}充电");
        }
    }
}

 3.3.电话本接口实现

namespace UnityUse.Service
{
    public class PhoneBookService : IPhoneBookService
    {
        /// <summary>
        /// 电话本服务构造函数
        /// </summary>
        public PhoneBookService()
        {
            Console.WriteLine($"{nameof(PhoneBookService)}构造");
        }

        /// <summary>
        /// 打开电话本
        /// </summary>
        public void Open()
        {
            Console.WriteLine($"{nameof(PhoneBookService)}打开电话本");
        }
    }
}

 3.4.耳机接口实现

namespace UnityUse.Service
{
    public class EarphoneService : IEarphoneService
    {
        /// <summary>
        /// 耳机服务构造函数
        /// </summary>
        public EarphoneService()
        {
            Console.WriteLine($"{nameof(EarphoneService)}构造");
        }

        /// <summary>
        /// 戴上耳机
        /// </summary>
        public void PutOn()
        {
            Console.WriteLine($"{nameof(EarphoneService)}戴上耳机");
        }
    }
}

 四.调用

namespace UnityUse
{
    class Program
    {
        static void Main(string[] args)
        {
            //1、实例化容器
            IUnityContainer container = new UnityContainer();
            //2、注册类型,但凡要用的类型,都需要注册,否则容器怎么工作呢
            container.RegisterType<IPhoneService, ApplePhoneService>();
            container.RegisterType<IPowerService, ApplePowerService>();
            container.RegisterType<IPhoneBookService, PhoneBookService>();
            container.RegisterType<IEarphoneService, EarphoneService>();
            //3、获取实例
            IPhoneService iPhone = container.Resolve<IPhoneService>();
            iPhone.Call();
            Console.ReadLine();
        }
    }
}

 五.效果图

5.1.在构造ApplePhoneService的时候,先去构造了ApplePowerService,也就是先构造了电源对象。

5.2.在构造完ApplePhoneService后,又紧跟着构造了PhoneBookService,也就是构造了电话本对象,因为构造顺序是构造函数注入--属性注入--方法注入

5.3.在构造完PhoneBookService后,最后构造了EarphoneService,我们在调用的时候没有主动去调用EarphoneCall方法,但是因为EarphoneCall标记了InjectionMethod特性,所以会注入方法的依赖对象,也就同时会调用该方法。

 

六.总结

6.1.注册类型的时候

没有抽象实现不行,没有父子关系不行,但凡要用的类型,都需要注册,否则容器怎么工作呢?

6.2.为什么要标记特性

因为那么多属性,那么多构造函数,容器怎么知道要构造哪一个呢?所以需要用特性标记一下。

6.3.构造函数比较特殊

特殊在就算没有标记特性,容器默认构造找参数最多的构造函数,可以不用特性,不用特性意味着可以去掉对容器的依赖