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