IOC---符合开闭原则OCP


    public class Person
    {
        public AndroidPhone Phone { get; set; }

        public void CallForSomebody()
        {
            Phone.Call();
        }
    }

    public class AndroidPhone
    {
        public void Call()
        {
            Console.WriteLine($"{this.GetType().Name} is calling");
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            Person person = new Person
            {
                Phone = new AndroidPhone()
            };
            person.CallForSomebody();
            Console.ReadKey();
        }
    }
复制代码
如果这时候,想给这个人一部苹果手机,那么必须要修改 Person 类, 将属性Phone的类型改成:ApplePhone.这显然违背了OOP思想的"对修改封闭,对扩展开放"原则.同时该代码也不符合"接口分离原则",于是乎做如下调整.

版本2.0
复制代码
    public class Person
    {
        //定义 Phone 为 接口 IPhone 类型
        public IPhone Phone { get; set; }

        public void CallForSomebody()
        {
            Phone.Call();
        }
    }

    public interface IPhone
    {
        void Call();
    }

    public class ApplePhone : IPhone
    {
        public void Call()
        {
            Console.WriteLine($"{this.GetType().Name} is calling");
        }
    }

    public class AndroidPhone : IPhone
    {
        public void Call()
        {
            Console.WriteLine($"{this.GetType().Name} is calling");
        }
    }

控制台程序:
            Person person = new Person();

            //给这个人一部安卓手机
            person.Phone = new AndroidPhone();
            person.CallForSomebody();

            //给这个人一部苹果手机
            person.Phone = new ApplePhone();
            person.CallForSomebody();
复制代码
如果需要给诺基亚手机,只需要在创建一个诺基亚Phone类,实现  IPhone 接口,而不需要修改底层代码.

依赖注入有三种方式:
复制代码
    public class Person
    {
        //属性注入
        public IPhone Phone { get; set; }

        //构造函数注入
        public Person(IPhone phone)
        {
            this.Phone = phone;
        }

        //方法注入
        public void MethodInject(IPhone phone)
        {
            this.Phone = phone;
        }
        
        public void CallForSomebody()
        {
            Phone.Call();
        }
    }
复制代码
版本2.0虽然不需要修改底层代码,但是控制台的代码依然需要修改,我们需要将 new AndridPhone() 更改成 new ApplePhone()

版本3.0 ( 利用 Unity )
学习新东西都是从 hello world 开始,先来一段 Unity 的 hello world

复制代码
            //创建一个IOC容器
            IUnityContainer container = new UnityContainer();

            //想要安卓手机就注册安卓手机
            //container.RegisterType<IPhone, AndroidPhone>();

            //想要苹果手机就注册苹果手机
            container.RegisterType<IPhone, ApplePhone>();

            IPhone phone = container.Resolve<IPhone>();

            Person person = new Person(phone);
            person.CallForSomebody();
复制代码
这段代码其实 跟 版本2.0没什么区别,甚至还复杂了,版本2.0是改 new AndroidPhone() ,  这里是改  container.RegisterType<IPhone, AndroidPhone>() 

版本4.0
新建一个配置文件:



按 Ctrl+C 复制代码

<?xml version="1.0" encoding="utf-8" ?>
<configuration>

  <configSections>
    <section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection,Microsoft.Practices.Unity.Configuration"/>
  </configSections>

  <unity xmlns="http://schemas.microsoft.com/practices/2010/unity">
    <containers>
      <container name="unityContainer">
        <!--type,mapTo:逗号左边是类的完全限定名,即命名空间+类名;逗号右边是程序集名称-->
        <register type="IOCUnity.IPhone,IOCUnity" mapTo="IOCUnity.AndroidPhone,IOCUnity"></register>
      </container>
    </containers>
  </unity>

</configuration>
按 Ctrl+C 复制代码
控制台代码如下:

复制代码
            ExeConfigurationFileMap fileMap = new ExeConfigurationFileMap
            {
                ExeConfigFilename = Path.Combine(AppDomain.CurrentDomain.BaseDirectory + @"UnityXml\UnityConfig.xml")
            };
            Configuration configuration = ConfigurationManager.OpenMappedExeConfiguration(fileMap,ConfigurationUserLevel.None);
            UnityConfigurationSection section = (UnityConfigurationSection)configuration.GetSection(UnityConfigurationSection.SectionName);

            IUnityContainer container = new UnityContainer();
            section.Configure(container, "unityContainer");
            IPhone phone = container.Resolve<IPhone>();

            Person person = new Person(phone);
            person.CallForSomebody();
复制代码
如果要换成 ApplePhone , 只需要将 配置文件中  mapTo="IOCUnity.AndroidPhone,IOCUnity" 更改成 mapTo="IOCUnity.ApplePhone,IOCUnity"> 即可,源代码不需要做任何修改

版本4.5
配置文件修改: 添加 name 标记

        <register type="IOCUnity.IPhone,IOCUnity" mapTo="IOCUnity.ApplePhone,IOCUnity" name="Apple"></register>
        <register type="IOCUnity.IPhone,IOCUnity" mapTo="IOCUnity.AndroidPhone,IOCUnity" name="Android"></register>
 

            //创建一个安卓手机
            //IPhone phone = container.Resolve<IPhone>("Android");

            //创建一个苹果手机
            IPhone phone = container.Resolve<IPhone>("Android");
版本5.0
控制台代码:

复制代码
            ExeConfigurationFileMap fileMap = new ExeConfigurationFileMap
            {
                ExeConfigFilename = Path.Combine(AppDomain.CurrentDomain.BaseDirectory + @"UnityXml\UnityConfig.xml")
            };
            Configuration configuration = ConfigurationManager.OpenMappedExeConfiguration(fileMap, ConfigurationUserLevel.None);
            UnityConfigurationSection section = (UnityConfigurationSection)configuration.GetSection(UnityConfigurationSection.SectionName);

            IUnityContainer container = new UnityContainer();
            section.Configure(container, "unityContainer");

            Person person = container.Resolve<Person>();
            /*
            上面创建了一个person,虽然我们没有给它的属性Phone赋值,但实际上 Unity 已经帮我们注入了.
            Unity 有三种特性 分别对应三种注入方式:
            [InjectionConstructor] 构造函数注入 
            [dependency]           属性注入
            [InjectionMethod]      方法注入
            如果一个特性都不打,那么Unity 默认会采用 构造函数注入,并且是选用入参最多的那个构造函数注入.因此,推荐采用 构造函数注入,因为它是无侵入式的,不需要打任何特性.
             */
            person.CallForSomebody();
复制代码
 

复制代码
    public class Person
    {

        //属性注入
        [Dependency]
        public IPhone Phone { get; set; }

        //构造函数注入
        [InjectionConstructor]
        public Person(IPhone phone)
        {
            this.Phone = phone;
        }

        //方法注入
        [InjectionMethod]
        public void MethodInject(IPhone phone)
        {
            this.Phone = phone;
        }

        public void CallForSomebody()
        {
            Phone.Call();
        }
    }
复制代码
 

复制代码
<?xml version="1.0" encoding="utf-8" ?>
<configuration>

  <configSections>
    <section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection,Microsoft.Practices.Unity.Configuration"/>
  </configSections>

  <unity xmlns="http://schemas.microsoft.com/practices/2010/unity">
    <containers>
      <container name="unityContainer">
        <!--type,mapTo:逗号左边是类的完全限定名,即命名空间+类名;逗号右边是程序集名称-->
        <register type="IOCUnity.IPhone,IOCUnity" mapTo="IOCUnity.ApplePhone,IOCUnity"></register>
        <register type="IOCUnity.Person,IOCUnity" mapTo="IOCUnity.Person,IOCUnity"></register>
      </container>
    </containers>
  </unity>

</configuration>
复制代码
 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值