最新QQ弹窗弹了个腾讯课堂的推广消息,就点进去看了。里面琳琅满目,有着各种方面的免费基础教学。好奇心驱使,报名了一个.net的基础课堂,并加了群。群里很多都是在校学生和初学开发的朋友。看到他们和我初学时一样,对多态的理解很模糊,所以想写此博文。一来把自己的理解共享给大家,二来可以巩固自己所学,此为背景。
让我们先来看看多态到底能够给我们带来什么好处。
以一个飞机控制系统,需要让所有的飞机都可以飞起来。这是最容易想到的写法:
/// <summary> /// 所有飞机的基类 /// </summary> public class PlaneBase { public static PlaneBase GetPlane(string planeName) { switch(planeName) { case "喷气机": return new Jet(); case "直升机": return new Copter(); } return null; } /// <summary> /// 起飞 /// </summary> public void Fly() { Console.WriteLine("起飞了!"); } }
所有飞机的父类
/// <summary> /// 喷气机 /// </summary> public class Jet : PlaneBase { }
喷气机
/// <summary> /// 直升机 /// </summary> public class Copter : PlaneBase { }
直升机
static void Main(string[] args) { PlaneBase jet = PlaneBase.GetPlane("喷气机"); jet.Fly(); PlaneBase copter = PlaneBase.GetPlane("直升机"); copter.Fly(); }
控制飞机起飞
我们利用了继承的特性,通过一个父类,让所有子类都自动具有了起飞的方法。
但是我们很快发现了问题,直升机和喷气机的起飞方式不一样啊,喷气机是向前加速起飞的,直升机是直上的。
于是我们修改我们的代码,在子类分别实现自己的起飞方法:
/// <summary> /// 喷气机 /// </summary> public class Jet : PlaneBase { public void Fly() { Console.WriteLine("喷气机起飞了!"); } }
喷气机
/// <summary> /// 直升机 /// </summary> public class Copter : PlaneBase { public void Fly() { Console.WriteLine("直升机起飞了!"); } }
直升机
static void Main(string[] args) { Jet jet = new Jet(); jet.Fly(); //喷气机起飞 Copter copter = new Copter(); copter.Fly(); //直升机起飞 }
控制飞机起飞
再次调试,哈,这次成功了,直升机和喷气机都按照自己的起飞方式起飞了。
可是问题又来了,仔细对比两次控制飞机飞行的代码,发现区别了吗?
我们控制的时候,不得不事先知道这是个什么样的飞机(具体的飞机对象),再去控制它起飞;这一定是控制者的恶梦。
多态的强大之处就在此体现出来了,先来看看修改后的代码。
/// <summary> /// 所有飞机的基类 /// </summary> public class PlaneBase { public static PlaneBase GetPlane(string planeName) { switch(planeName) { case "喷气机": return new Jet(); case "直升机": return new Copter(); } return null; } /// <summary> /// 起飞 /// </summary> public virtual void Fly() { Console.WriteLine("起飞了!"); } }
所有飞机的父类
/// <summary> /// 喷气机 /// </summary> public class Jet : PlaneBase { public override void Fly() { Console.WriteLine("喷气机起飞了!"); } }
喷气机
/// <summary> /// 直升机 /// </summary> public class Copter : PlaneBase { public override void Fly() { Console.WriteLine("直升机起飞了!"); } }
直升机
static void Main(string[] args) { PlaneBase jet = PlaneBase.GetPlane("喷气机"); jet.Fly(); PlaneBase copter = PlaneBase.GetPlane("直升机"); copter.Fly(); Console.ReadLine(); }
控制飞机起飞
我们在父类的Fly方法前加上了virtual关键字,将它标识为一个虚方法,然后在子类的Fly方法前加上了override关键字,意味着覆盖父类的方法(重写)。
现在,我们的控制者只需要获取一个飞机(PlaneBase.GetPlane方法),并不需要关心获取到的到底是直升机还是喷气机,只要让它起飞(调用Fly方法),飞机就会按照自己的的起飞方式起飞了(程序自动调用对应子类的Fly方法)。
就这样简单,但好处却是显而易见。
如何实现多态?
1. 存在一个继承体系结构。如果不存在继承体系结构,那么所谓的多态就无从谈起。
2. 把我们需要的统一的接口(方法)在父类中定义,并标记为虚方法。
3. 子类重写该方法。
这只是多态最最基本的一种实现,也是用得最多的。
那我们在什么时候需要用到多态呢?
简单来说就是,当接口确定,而在不同环境中需要不同实现的时候,我们就要用到多态了。比如操作数据库的时候,我们只需要使用数据库父对象,调用一个统一的接口,就可以使用增删改查,不需要关心数据库到底是Sqlserver还是oracle,真正的数据库操作放到对应数据库的子类去实现;