C# 多态(一)

面向对象三大特性:封装,继承,多态


封装: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("我是一只企鹅,我喜欢吃鱼");
        }
    }

}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值