• 接口与单元测试


    接口的本质是契约(contract),双方都可见。

    求数组中的数字之和和平均数

    不同类型的数组,不同方法

    using System;
    using System.Collections;
    
    namespace March9
    {
        internal class Program
        {
            public 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));
            }
    
            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;
            }
            
        }
    }
    

    利用接口

    using System;
    using System.Collections;
    
    namespace March9
    {
        internal class Program
        {
            public static void Main(string[] args)
            {
                int[] nums1 = new int[] {1, 2, 3, 4, 5};
                ArrayList nums2 = new ArrayList {1, 2, 3, 4, 5,6};//ArrayList,array继承自IEnumerable接口
                Console.WriteLine(Sum(nums2));
                Console.WriteLine(Avg(nums2));
            }
    
            static int Sum(IEnumerable nums)
            {
                int sum = 0;
                foreach (var n in nums)
                {
                    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;
            }
            
        }
    }
    

    接口是为松耦合而生的,方便功能的可替换性,

    using System;
    using System.Collections;
    
    namespace March9
    {
        internal class Program
        {
            public static void Main(string[] args)
            {
                var user=new User(new VIVO());//实现用户使用不同的手机打电话,发信息
                user.Userphone();
            }
    
        }
    
        class User
        {
            private IPhone _phone;
            public User(IPhone phone)//接收接口类型的变量
            {
                _phone = phone;
            }
            public void Userphone()
            {
                _phone.Dial();
                _phone.Pickup();
                _phone.Send();
                _phone.Receive();
            }
            
        }
    
    
        interface IPhone
        {
            void Dial();//拨号
            void Pickup();//接听
            void Send();//发送
            void Receive();//接收
        }
    
        class NokiaPhone:IPhone
        {
            public void Dial()
            {
                Console.WriteLine("Nokia is calling");
            }
            public void Pickup()
            {
                Console.WriteLine("hello,tim");
            }
            public void Send()
            {
                Console.WriteLine("Nokia is ring");
            }
            public void Receive()
            {
                Console.WriteLine("hello,maray");
            }
        }
        
        class VIVO:IPhone
        {
            public void Dial()
            {
                Console.WriteLine("VIVO is calling");
            }
            public void Pickup()
            {
                Console.WriteLine("hello");
            }
            public void Send()
            {
                Console.WriteLine("Vivo is send");
            }
            public void Receive()
            {
                Console.WriteLine("Vivo is receiving");
            }
        }
        
        
    }
    

    语言对面向对象设计的内建支持:依赖反转,接口隔离,开闭原则……

    依赖反转

    被依赖的再下面,上面是司机下面的是车。Driver里有一个car类型的字段,他们是紧耦合的。这种情况下每一个人只能开对应的车,不能开其他的车

    Driver里的字段不再是car等车的类型,而是一个基接口,去调用各种车里的run方法,出现了依赖反转。

    当多个服务的提供者和服务的使用者都遵循一个接口时,就可以进行多种配对。通过接口作为桥梁,实现调用不同实例的方法。

    接口隔离

    契约:甲方(派生类)不会多要,乙方(接口)不会少给。如果一直没有调用,就说明他是多余的,是个胖接口。
    单一职责原则,一个类只做一件事。
    例子:让一个人开多种交通工具

    using System;
    
    namespace March10
    {
        internal class Program
        {
            public static void Main(string[] args)
            {
                var a=new Driver(new Car());//此时car类和Truck都能开汽车,因为他继承自IVhicle接口,如果我想开坦克呢?那么就要改变Driver引用实例的变量的类型。
                a.Drive();
            }
        }
    
    
        class Driver
        {
            private IVehicle _vehicle;//此时,IVehicle类型的变量能引用继承自IVhicle接口实例的方法;ITank类型的变量能引用继承自ITank接口的实例的方法
    
            public Driver(IVehicle vehicle)
            {
                _vehicle = vehicle;
            }
    
            public void Drive()
            {
                _vehicle.Run();
            }
    
    
        }
    
        interface IVehicle
        { 
            void Run();
        }
    
        class Car:IVehicle
        {
            public void Run()
            {
                Console.WriteLine("car is runnning!");
            }
        }
    
        class Truck:IVehicle
        {
            public void Run()
            {
                Console.WriteLine("truck is running!");
            }
        }
    
        interface ITank
        {
            void Fire();
            void Run();
        }
    
        class LightTank:ITank
        {
            public void Fire()
            {
                Console.WriteLine("开炮");
            }
    
            public void Run()
            {
                Console.WriteLine("ka……ka……ka");
            }
        }
    }
    

    上面这种换来换取的方法很麻烦,问题就是传进去了胖接口,fire()方法用不到,因为功能不同,我只想开车,而不是开火做其他的事。
    把fire()方法单独做一个接口,然后让ITank接口继承两个基接口。接口是可以多重继承的,而类不行。

    using System;
    
    namespace March10
    {
        internal class Program
        {
            public static void Main(string[] args)
            {
                var a=new Driver(new Car());
                a.Drive();
            }
        }
    
    
        class Driver
        {
            private IVehicle _vehicle;
    
            public Driver(IVehicle vehicle)
            {
                _vehicle = vehicle;
            }
    
            public void Drive()
            {
                _vehicle.Run();
            }
    
    
        }
    
        interface IVehicle
        { 
            void Run();
        }
        interface Single
        { 
            void Fire();
        }
    
        class Car:IVehicle
        {
            public void Run()
            {
                Console.WriteLine("car is runnning!");
            }
        }
    
        class Truck:IVehicle
        {
            public void Run()
            {
                Console.WriteLine("truck is running!");
            }
        }
    
        interface ITank:IVehicle,Single
        {
        }
    
        class LightTank:ITank
        {
            public void Fire()
            {
                Console.WriteLine("开炮");
            }
    
            public void Run()
            {
                Console.WriteLine("ka……ka……ka");
            }
        }
    }
    

    此时,我们调用ITank接口的时候,只关注了里面的继承自IVhicle的run方法,Driver只调用run方法,服务的调用者不会多要。
    问题又来了,如果我们把Driver类里的改为private ITank _vehicle;构造器的变量类型改变了,那么会发现,car和truck类的run方法无法调用,因为接口用的太大了,应该传小接口。

    using System;
    using System.Collections;
    
    namespace March10
    {
        internal class Program
        {
            public static void Main(string[] args)
            {
                int[] nums1 = new int[] {1, 2, 3, 4, 5};
                ArrayList nums2 = new ArrayList {1, 2, 3, 4,5,6};//ArrayList,array继承自IEnumerable接口
                var nums3=new ReadOnlyCollection(nums1);
                Console.WriteLine(Sum(nums1));
                foreach (var n in nums3)
                {
                    Console.WriteLine(n);
                }
            }
    
            static int Sum(ICollection nums)
            {
                int sum = 0;
                foreach (var n in nums)
                {
                    sum +=(int) n;
                }
                return sum;
            }
    
            
        }
    
        public class ReadOnlyCollection:IEnumerable
        {
            private int[] _array;
    
            public ReadOnlyCollection(int[] array)
            {
                _array = array;//接受过来的数组只读
            }
            public IEnumerator GetEnumerator()
            {
                return new Enumerator(this);
            }
    
            
            //成员类
            public class Enumerator:IEnumerator
            {
                private ReadOnlyCollection _collection;
                private int _head;
                public Enumerator(ReadOnlyCollection collection)
                {
                    _collection = collection;
                    _head = -1;
                }
                public bool MoveNext()
                {
                    if (++_head < _collection._array[_head])
                    {
                        return true;
                    }
                    else
                    {
                        return false;
                    }
                }
    
                public void Reset()
                {
                    _head = -1;
                }
    
                public object Current
                {
                    get
                    {
                        object o = _collection._array[_head];
                        return o;
                    }
                } //只读属性
            }
        }
        
        
    }
    

    sum方法里需要循环然后再加,所以参数只需要迭代就可以了,但是他的参数类型设计成了IColllection,导致符合迭代要求的IEnumerable类型的参数无法传进来,就这是所谓的“使用方要求过多”。
    改为static int Sum(IEnumerable nums) { }就可以了
    接口的显示与隐式

    using System;
    
    namespace March11
    {
        internal class Program
        {
            public static void Main(string[] args)
            {
                var kill=new Kill1();
                kill.love();//此时看不到kill方法
                IKiller k = kill;
                k.kill();//此时看不到love方法
    
            }
        }
    
    
        interface IGentleman
        {
            void love();
        }
    
        interface IKiller
        {
            void kill();
        }
    
    
        class Kill1 : IGentleman,IKiller
        {
            public void love()
            {
                Console.WriteLine("I love you");
            }
    
            void IKiller.kill()
            {
                Console.WriteLine("I will kill you");
            }
        }
        
        
    }
    
  • 相关阅读:
    R语言--数据预处理
    R语言学习笔记——数据结构 & 数据框基本操作
    R—读取数据(导入csv,txt,excel文件)
    GA算法-R语言实现
    关联规则-R语言实现
    R语言-妹子被追后的选择分析
    使用R的networkD3包画可交互的网络图
    用R进行市场调查和消费者感知分析
    笔记
    Mysql4:查询数据
  • 原文地址:https://www.cnblogs.com/lpxspring/p/12448049.html
Copyright © 2020-2023  润新知