接口与单元测试

接口的本质是契约(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方法无法调用,因为接口用的太大了,应该传小接口。

猜你喜欢

转载自www.cnblogs.com/lpxspring/p/12448049.html
今日推荐