2021-06-26-刘铁猛C#语言入门详解-学习笔记P28接口、依赖反转、单元测试

P28接口、依赖反转、单元测试

回溯记录:
2021/12/27回溯

一、P28内容总结

  1. 接口
  2. 依赖与耦合
  3. 依赖反转原则(SOLID中的D)
  4. 单元测试

二、接口:服务的提供者实现接口,服务的消费者引用接口
//实例:对一组整数进行求和与求平均值的操作
//这组整数可能存于数组也可能存于ArrayList里

方法一:不使用接口时

using System;
using System.Collections;//为引入ArrayList

namespace ConsoleApp3
{
    class Program
    {
        static void Main(string[] args)
        {
            int[] nums1 = new int[] { 1, 2, 3, 4, 5 };
            ArrayList nums2 = new ArrayList { 1, 2, 3, 4, 5 };
            Console.WriteLine(Sum(nums1));
            Console.WriteLine(Avg(nums1));
            Console.WriteLine(Sum(nums2));
            Console.WriteLine(Avg(nums2));
        }
        
        static int Sum(int[] nums)
        {
            int sum = 0;
            foreach (var n in nums)
            {
                sum += n;
            }
            return sum;
        }

        static double Avg(int[] nums)
        {
            int sum = 0;
            double count = 0;
            foreach (var n in nums)
            {
                sum += n;
                count++;
            }
            return sum / count;
        }

        static int Sum(ArrayList nums)
        {
            int sum = 0;
            foreach (var n in nums)
            {
                //ArrayList元素是object类型,需要进行类型转换
                sum += (int)n;
            }
            return sum;
        }

        static double Avg(ArrayList nums)
        {
            int sum = 0;
            double count = 0;
            foreach (var n in nums)
            {
                sum += (int)n;
                count++;
            }
            return sum / count;
        }
    }
}
方法二:使用接口时
服务的提供者、服务的需求者需要满足同一个协议
此处==数据提供者与求和求平均操作需求者都满足,IEnumerable可进行简单迭代

using System;
using System.Collections;

namespace ConsoleApp3
{
    class Program
    {
        static void Main(string[] args)
        {
            int[] nums1 = new int[] { 1, 2, 3, 4, 5 };
            ArrayList nums2 = new ArrayList { 1, 2, 3, 4, 5 };
            Console.WriteLine(Sum(nums1));
            Console.WriteLine(Avg(nums1));
            Console.WriteLine(Sum(nums2));
            Console.WriteLine(Avg(nums2));
        }
        static int Sum(IEnumerable nums)
        {
            int sum = 0;
            foreach (var n in nums)
            {
                //ArrayList元素是object类型,需要进行类型转换
                sum += (int)n;
            }
            return sum;
        }

        static double Avg(IEnumerable nums)
        {
            int sum = 0;
            double count = 0;
            foreach (var n in nums)
            {
                sum += (int)n;
                count++;
            }
            return sum / count;
        }
    }
}

三、依赖与耦合
紧耦合弊端:出错时,因为类与类之间的依赖关系太强,错误难以被发现

实例:车辆行驶过程中转速问题
例子中的Car类型与Engine类型就是依赖关系,紧耦合

using System;

namespace ConsoleApp3
{
    class Program
    {
        static void Main(string[] args)
        {
            Engine engine = new Engine();
            Car car = new Car(engine);
            car.Run(3);
            Console.WriteLine(car.Speed);
            
        } 
    }
    
    class Engine
    {
        //设置转速属性,由于转速不可从外部设置加上private修饰符
        //Work 方法,输入油门大小
        public int RPM { get; private set; }
        public void Work(int gas)
        {
            this.RPM = gas * 1000;
        }
    }

    class Car
    {
        private Engine _engine;
        public Car(Engine engine)
        {
            _engine = engine;
        }

        public int Speed { get; private set; }
        //车子发动代表引擎开始工作,输入油门大小得到转速获得车的速度
        public void Run(int gas)
        {
            _engine.Work(gas);
            this.Speed = _engine.RPM / 100;
        }
     }       
}

解决紧耦合:引入 接口,使功能的提供方变得可替换,紧耦合时功能提供方难以被替换

实例:不同品牌手机实现接电话、打电话、发消息、收消息

using System;

namespace ConsoleApp3
{
    class Program
    {
        static void Main(string[] args)
        {
        	XiaoMiPhone xiaomi = new XiaoMiPhone();
            PhoneUser user = new PhoneUser(xiaomi);
            //PhoneUser user = new PhoneUser(new XiaoMiPhone());
            
            user.UsePhone();
        } 
    }

    //创建用户类
    class PhoneUser
    {
        private IPhone _phone;
        public PhoneUser(IPhone phone)
        {
            _phone = phone;
        }
        public void UsePhone()
        {
            _phone.Dail();
            _phone.PickUp();
            _phone.Receive();
            _phone.Send();
        }
    }
    
    interface IPhone
    {
        void Dail();
        void PickUp();
        void Receive();
        void Send();
    }
    
    class XiaoMiPhone : IPhone
    {
        public void Dail()
        {
            Console.WriteLine("XiaoMi calling.... "); 
        }

        public void PickUp()
        {
            Console.WriteLine("Hello!This is Tim!"); 
        }

        public void Receive()
        {
            Console.WriteLine("XiaoMi message ring.....");
        }

        public void Send()
        {
            Console.WriteLine("Hello!");
        }
    }

    class HuaWeiPhone : IPhone
    {
        public void Dail()
        {
            Console.WriteLine("HuaWei calling.....");
        }

        public void PickUp()
        {
            Console.WriteLine("Hello!This is Tim!");
        }

        public void Receive()
        {
            Console.WriteLine("HuaWei message ring.....");
        }

        public void Send()
        {
            Console.WriteLine("Good evening!");
        }
    }
}

四、依赖反转原则(SOLID中的D)
2021-06-26-刘铁猛C#语言入门详解-学习笔记P28接口、依赖反转、单元测试_第1张图片
图片说明:个人理解,仅供参考
[part1] 特定驾驶员依赖特定驾驶方式的特定启动。
例:小车/卡车/赛车驾驶员拥有小车,驾驶小车/卡车/赛车时调用小车/卡车/赛车的启动方式;
[part2] 设置了一种接口,包含各类车的启动方式,小车驾驶员驾驶时通过调用接口中包含的各类车启动方式启动不同的车;
[part3] *2的对应关系

实例:电扇生产厂商,通过控制电流大小控制电扇的转速

//紧耦合
using System;

namespace ConsoleApp3
{
    class Program
    {
        static void Main(string[] args)
        {
            DaskFan fan = new DaskFan(new PowerSupply());
            Console.WriteLine(fan.Work()); 
        } 
    }
    
    class PowerSupply
    {
        public int GetPower()
        {
            return 100;
        }
    }

    class DaskFan
    {
        private PowerSupply _powerSupply;
        
        public DaskFan(PowerSupply powerSupply)
        {
            _powerSupply = powerSupply;
        }

        public string Work()
        {
            int power = _powerSupply.GetPower();
            if(power <=0)
            {
                return "Won't work.";
            }
            else if(power <= 100)
            {
                return "Slow.";
            }
            else if (power <= 200)
            {
                return "Work fine.";
            }
            else
            {
                return "Warning.";
            }
 
        }    
    }
}
//引入接口
using System;

namespace ConsoleApp3
{
    class Program
    {
        static void Main(string[] args)
        {
            DaskFan fan = new DaskFan(new PowerSupply());
            Console.WriteLine(fan.Work()); 
        } 
    }

    interface IPowerSupply
    {
        int GetPower();
    }

    public class PowerSupply:IPowerSupply
    {
        public int GetPower()
        {
            return 100;
        }
    }

    public class DaskFan
    {
        private IPowerSupply _powerSupply;

        public DaskFan(IPowerSupply powerSupply)
        {
            _powerSupply = powerSupply;
        }

        public string Work()
        {
            int power = _powerSupply.GetPower();
            if(power <=0)
            {
                return "Won't work.";
            }
            else if(power <= 100)
            {
                return "Slow.";
            }
            else if (power <= 200)
            {
                return "Work fine.";
            }
            else
            {
                return "Warning.";
            }
        } 
    }
}

五、单元测试

  1. 单元测试是依赖反转原则的直接受益者
  2. 创建单元测试项的步骤
    1)右击solution添加新的项目xUnit测试项目
    2)右击测试项目中的依赖项,添加需要测试的项目
  3. 实例:测试上面电扇项目输入的电压是否小于0(这部分可能后面做项目用到才能够理解,我是一知半解)

方法一:

using ConsoleApp3;
using System;
using Xunit;

namespace InterfaceTestProject1
{
    public class DeskFanTests
    {
        [Fact]
        public void PowerLowerThanZero_OK()
        {
            DaskFan fan = new DaskFan(new PowerSupplyLowerThanZero());
            var expected = "Won't work.";
            var actual = fan.Work();
            Assert.Equal(expected, actual);
        }
    }
    class PowerSupplyLowerThanZero:IPowerSupply
    {
        public int GetPower()
        {
            return 0;
        }
    }
}

方法二:使用moq(暂时不考虑用这种,先把简单的学好吧)

你可能感兴趣的:(刘铁猛C#语言入门详解,c#)