• C# Ioc、DI、Unity、TDD的一点想法和实践


    面向对象设计(OOD)有助于我们开发出高性能、易扩展以及易复用的程序。其中,OOD有一个重要的思想那就是依赖倒置原则(DIP)。

    依赖倒置原则(DIP):一种软件架构设计的原则(抽象概念)

    控制反转(IoC):一种反转流、依赖和接口的方式(DIP的具体实现方式)

    依赖注入(DI):IoC的一种实现方式,用来反转依赖(IoC的具体实现方式)

    IoC容器:依赖注入的框架,用来映射依赖,管理对象创建和生存周期(DI框架)、

    Unity:是微软推出的IOC框架

    TDD:测试驱动开发,是敏捷开发中的一项核心实践和技术,也是一种设计方法论

    上面的内容都是抄的(英文不好,放在这里备查),相关的内容看了一些,不明觉厉。

    曾经写了一个酒店读写房卡的程序,不同的酒店门锁是不一样的,同一个酒店也有可能更换门锁,程序流程:

    1.通过Api获取当前酒店的门锁类型

    2.如果需要则下载对应门锁的dll

    3.实现读写功能

    一、定义接口

    新建一个类库(Lock.Interface),代码如下:

    namespace Lock
    {
        public interface ILock
        {
            /// <summary>
            /// 门锁初始化
            /// </summary>
            /// <param name="password">初始化密码</param>
            /// <returns></returns>
            bool Init(int password);
    
        }
    }

    是不是算是IoC了?(我不确定)

    二、单元测试

    新建一个单元测试项目(Lock.Tests),代码如下:

    1.门锁A单元测试

        /// <summary>
        /// 门锁A测试
        /// </summary>
        [TestClass()]
        public class LockATests
        {
            /// <summary>
            /// 初始化,password为正奇数
            /// </summary>
            [TestMethod()]
            public void InitTest()
            {
                ILock l = new LockA();
                var ret = l.Init(1);
                Assert.AreEqual(ret, true);
                ret = l.Init(2);
                Assert.AreEqual(ret, false);
                ret = l.Init(-1);
                Assert.AreEqual(ret, false);
            }
    
        }

    2.门锁B单元测试

        /// <summary>
        /// 门锁B测试
        /// </summary>
        [TestClass()]
        public class LockBTests
        {
            /// <summary>
            /// 初始化测试,password为正偶数
            /// </summary>
            [TestMethod()]
            public void InitTest()
            {
                ILock l = new LockB();
                var ret = l.Init(1);
                Assert.AreEqual(ret, false);
                ret = l.Init(2);
                Assert.AreEqual(ret, true);
                ret = l.Init(-1);
                Assert.AreEqual(ret, false);
            }

    显然编译都不能通过(不能通过编译也是一种测试)

    三、定义类

     1.创建门锁A类库(Lock.LockA),代码如下:

        /// <summary>
        /// 门锁A
        /// </summary>
        public class LockA : ILock
        {
            
            /// <summary>
            /// 初始化
            /// </summary>
            /// <param name="password">正确密码是正奇数</param>
            /// <returns></returns>
            public bool Init(int password)
            {
                return password > 0 && (password % 2) == 1;
            }
        }
    

    2.创建门锁B类库(Lock.LockB),代码如下:

        /// <summary>
        /// 门锁B
        /// </summary>
        public class LockB : ILock
        {
            /// <summary>
            /// 初始化
            /// </summary>
            /// <param name="password">正确密码是正偶数</param>
            /// <returns></returns>
            public bool Init(int password)
            {
                return password > 0 && (password % 2) == 0;
            }
        }

    分别编译成功后,回到测试项目,添加引用,编译通过,运行测试:

    算不算TDD?

    四、主程序

    1.添加控制台项目

    2.添加Unity(5.8.6)包

    3.修改App.Config为:

    <?xml version="1.0" encoding="utf-8" ?>
    <configuration>
      <configSections>
        <section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection,Unity.Configuration, Version=5.2.1.0, Culture=neutral, PublicKeyToken=6d32ff45e0ccc69f" />
        <!--上一些的内容网上复制过来有错误,后来查看UnityConfigurationSection的定义,复制了对应的程序集
        type="命名空间.类名,程序集"
        -->
      </configSections>
      <unity>
        <containers>
          <container name="LockA">
            <register type="Lock.ILock,Lock.Interface"  mapTo="Lock.LockA,Lock.LockA" ></register>
          </container>
          <container name="LockB">
            <register type="Lock.ILock,Lock.Interface"  mapTo="Lock.LockB,Lock.LockB"></register>
          </container>
        </containers>
      </unity>
      <startup>
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2" />
      </startup>
    </configuration>
    

    4.引用接口

    5.Main方法如下:

            static void Main(string[] args)
            {
                var container = new UnityContainer();
                UnityConfigurationSection config = (UnityConfigurationSection)ConfigurationManager.GetSection(UnityConfigurationSection.SectionName);
                config.Configure(container, "LockA");
    ILock l = container.Resolve<ILock>(); Console.WriteLine(l.Init(2)); Console.WriteLine(l.Init(1)); Console.WriteLine(l.Init(-1));
    Console.ReadKey(); }

    6.复制门锁A的dll复制到运行目录

    7.运行结果如为:False、True、False,是门锁A的结果

    8.将“LockA”改成“LockB”,并将门锁B的dll复制到运行目录,运行结果为True、False、False是门锁B的结果

    算DI吧?咱都用了Unity了。

    至此,基本实现了想要的功能,未来新酒店要增加门锁C、门锁D都没问题,只有老酒店改成门锁E的问题没解决(估计可以通过动态修改config文件实现,也不知道有没有更好地办法)。

  • 相关阅读:
    计算机中如何表示数字-01机器数与真值
    计算机中如何表示数字-06浮点数
    Java基础类型与其二进制表示
    char类型与Unicode的编码
    数组的详细总结
    Java中的instanceof关键字
    java 启动多线程
    elasticsearch7.2 集群搭建 插件安装 和kibana安装
    java读取 properties配置文件的两种方式
    查询mysql 库和表占的大小
  • 原文地址:https://www.cnblogs.com/catzhou/p/9048966.html
Copyright © 2020-2023  润新知