面向对象三大特性:封装,继承,多态
封装:1、在程序上,隐藏对象的属性和实现细节,仅对外公开接口,控制在程序中属性的读和修改的访问级别;将抽象得到的数据和行为(或功能)相结合,形成一个有机的整体,也就是将数据与操作数据的源代码进行有机的结合,形成“类”,其中数据和函数都是类的成员。
继承:指一个对象直接使用另一对象的属性和方法。
多态:是允许你将父对象设置成为和一个或更多的他的子对象相等的技术,赋值之后,父对象就可以根据当前赋值给它的子对象的特性以不同的方式运作。简单的说,就是一句话:允许将子类类型的指针赋值给父类类型的指针。
上述三个均为比较官方的解释。
而这里只讲多态
多态:允许将子类类型的指针赋值给父类类型的指针。即:同一操作作用于不同的对象,可以有不同的解释。
允许时,可以通过指向基类的指针,来调用实现派生类中的方法。
里氏替换原则:派生类(子类)对象能够替换其基类(超类)对象被使用。通俗来讲:子类即父类。
eg:男人是人,人不一定是男人。当需要一个父类类型的对象的时候可以给一个子类类型的对象;当需要一个子类类型对象的时候是不能给一个父类类型对象的!
开放封闭原则:封装变化,降低耦合。软件实体应该是可扩展,而不可修改。即:对扩展是开放的,对修改是封闭的。
因此开放封闭原则体现在:
1.对扩展开放,意味着有新的需求或变化时,可以对现有代码进行扩展,以适应新的情况。
2.对修改封闭,意味着类一旦设计完成,就可以独立完成其工作,而不要对类进行任何修改。
而多态的设计刚好符合上述两个原则
以鸟为例
我们知道,喜鹊(Magpie)、老鹰(Eagle)、企鹅(Penguin)均属于鸟类,根据三者共有特性提取出鸟类(Bird)为父类。
喜鹊喜欢吃虫子,老鹰喜欢吃肉,企鹅喜欢吃鱼。
先写一个父类Bird,创建Eat虚方法
再创建喜鹊,老鹰,企鹅三个子类,并重写Eat方法
至此,三个子类创建完毕,下面我们再看看主函数中多态是怎样体现的
运行:
由此可见,子类Magpie,Eagle,Penguin对象赋值给父类对象,即父类类型指针可以指向子类类型对象,这里体现了里氏替换原则。
父类对象调用自己的Eat()方法,实际上显示的是父类类型指针指向的子类类型对象重写父类Eat后的方法。这就是多态。
多态的作用到底是什么呢?
其实多态的作用就是把不同的子类对象都当作父类来看,可以屏蔽不同子类对象之间的差异,写出通用的代码,做出通用的编程,以适应需求的不断变化。
以上程序也体现了开放封闭原则,如果以后有人需要扩展这个程序,还想再添加一个猫头鹰(Owl),很容易,只需要添加一个Owl类,继承Bird,重写Eat()方法,添加给父类对象就可以了。至此,该程序的扩展性得到了提升,而又不需要查看源代码是如何实现的就可以扩展新功能。这就是多态带来的好处。
附代码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Polymorphism
{
class Program
{
static void Main(string[] args)
{
Bird[] birds ={
new Bird(),
new Magpie(),
new Eagle(),
new Penguin()
};
foreach(Bird bird in birds)
{
bird.Eat();
}
Console.ReadKey();
}
}
/// <summary>
/// 鸟类(父类)
/// </summary>
public class Bird
{
/// <summary>
/// 吃(虚方法)
/// </summary>
public virtual void Eat()
{
Console.WriteLine("我是一只鸟,我喜欢吃虫子");
}
}
/// <summary>
/// 喜鹊类(继承:鸟类)
/// </summary>
public class Magpie:Bird
{
/// <summary>
/// 吃(重写父类吃方法)
/// </summary>
public override void Eat()
{
Console.WriteLine("我是一只喜鹊,我喜欢吃虫子");
}
}
/// <summary>
/// 老鹰类(继承:鸟类)
/// </summary>
public class Eagle:Bird
{
/// <summary>
/// 吃(重写父类吃方法)
/// </summary>
public override void Eat()
{
Console.WriteLine("我是一只老鹰,我喜欢吃肉");
}
}
/// <summary>
/// 企鹅类(继承:鸟类)
/// </summary>
public class Penguin:Bird
{
/// <summary>
/// 吃(重写父类吃方法)
/// </summary>
public override void Eat()
{
Console.WriteLine("我是一只企鹅,我喜欢吃鱼");
}
}
}
下面我们再来看看利用抽象如何来实现多态。
刚才的例子中,我们发现Bird这个父类,我们根本不需要使用它创建的对象,它存在的意义就是供子类来继承。所以我们可以用抽象类来优化它。
我们把Bird父类改成抽象类,Eat()方法改成抽象方法。
抽象类Bird内添加一个Eat()抽象方法,没有方法体。也不能实例化。
其他类Magpie,Eagle,Penguin代码不变,子类还是用override关键字来重写父类中抽象方法。
这样,Bird类也就不能实例化了。
运行:
由此可见,我们选择使用虚方法实现多态还是抽象类抽象方法实现多态,取决于我们是否需要使用基类实例化的对象。
附代码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Polymorphism
{
class Program
{
static void Main(string[] args)
{
Bird[] birds ={
new Magpie(),
new Eagle(),
new Penguin()
};
foreach(Bird bird in birds)
{
bird.Eat();
}
Console.ReadKey();
}
}
/// <summary>
/// 鸟类(父类<抽象类>)
/// </summary>
public abstract class Bird
{
/// <summary>
/// 吃(抽象方法)
/// </summary>
public abstract void Eat();
}
/// <summary>
/// 喜鹊类(继承:鸟类)
/// </summary>
public class Magpie:Bird
{
/// <summary>
/// 吃(重写父类吃方法)
/// </summary>
public override void Eat()
{
Console.WriteLine("我是一只喜鹊,我喜欢吃虫子");
}
}
/// <summary>
/// 老鹰类(继承:鸟类)
/// </summary>
public class Eagle:Bird
{
/// <summary>
/// 吃(重写父类吃方法)
/// </summary>
public override void Eat()
{
Console.WriteLine("我是一只老鹰,我喜欢吃肉");
}
}
/// <summary>
/// 企鹅类(继承:鸟类)
/// </summary>
public class Penguin:Bird
{
/// <summary>
/// 吃(重写父类吃方法)
/// </summary>
public override void Eat()
{
Console.WriteLine("我是一只企鹅,我喜欢吃鱼");
}
}
}
2487

被折叠的 条评论
为什么被折叠?



