C#总结(面向对象基础)中

上篇博客主要介绍了对于一个类的声明,构造属性和方法。这篇博客中要介绍多个类时,如何处理类与类之间的关系。

一、继承

  上回(就是上篇博客)说到声明了一个猫类,如果再声明一个狗类可以直接将Cat改为Dog,叫声“喵”改为“汪”,就可以了。同样的如果再加上猪、牛、羊类的话,也可以直接改名字和叫声就可以了。但是这样就会造成相同的代码重复写很多遍。我们当然不会想要做机器要做的事情。前人已经提出了解决办法那就是继承。先抽象出猫、狗、猪、牛、羊这些动物的共同点,将这些共同点尽量都写在父类中。显然它们都属于动物,我们就将父类定义为动物类。

不用继承的话,如果要修改功能,就必须在所有重复的方法中修改,很有可能改了这个忘了那个,代码越多,出错的可能就越大,而继承的优点是,继承使得所有子类公共的部分都放在了父类,使得代码得到了共享,这就避免了重复,另外,继承可使得修改或扩展继承而来的实现都较为容易。


 class Animal//声明Animal类
        {
            protected string name = "";//修饰符改为了protect
            public Animal(string name)
            {
                this.name = name;
            }
            public Animal()
            {
                this.name = "无名";
            }
            protected int shoutNum = 3;//修饰符改为了protect
            public int ShoutNum
            {
                get
                {
                    return shoutNum;
                }
                set
                {
                    shoutNum = value; 
                }
            }


        }
       class Cat :Animal //继承格式是子类:父类
        {  
            public Cat()
                :base()     //子类构造方法需要调用父类同样参数类型的构造方法,用base关键字代表父类
            { }  
            public Cat(string name)
                : base(name)                
            { }
            public string Shout()   //声明猫叫的方法  
            {
                string result = ""; //声明字符串类型的result,用来记录猫叫次数的结果  
                for (int i = 0; i < shoutNum; i++)
                    result += "喵 ";

                return "我的名字叫" + name + "" + result;
            }
        }
       class Dog : Animal
       {
           public Dog()
               : base()
           { }
           public Dog(string name)
               : base(name)
           { }
           public string Shout()
           {
               string result = "";
               for (int i = 0; i < shoutNum; i++)
                   result += "汪";

               return "我的名字叫" + name + "" + result;
           }
       }
        private void button1_Click(object sender, EventArgs e)  
        {  
            Cat cat = new Cat("咪咪");
            cat.ShoutNum = 3;                              
            MessageBox.Show(cat.Shout());   
        }

        private void button2_Click(object sender, EventArgs e)
        {
            Dog dog = new Dog("大黄");
            dog.ShoutNum = 3;
            MessageBox.Show(dog.Shout());

        }  

运行结果如下



二、多态

不知道大家在敲完的上面的代码之后有没有想过,为什么不把Shout()方法也写到父类中,其中的大部分代码也都是重复的呀?它们只是叫声不同,猫是“喵”,狗是“汪”。这就涉及到多态了,相同的方法或操作作用到不同的对象身上会产生不同的效果,多态说起来的时候好像都懂,但是我们要学习的是写代码的时候到底怎么用呢?

这就需要我们了解虚方法和方法重写。我的理解虚方法就是在父类中声明这些方法但是父类并不用,这个方法对于父类来说就形同虚设而是留给子类用的。这样即使父类中不用这些方法,但是子类可以继承这些方法。需要用virtual关键字来实现。而子类再通过方法重写就可以使用父类中的虚方法了,虚方法要用override的关键字来写。刚开始我觉得是在Animal类中声明了shout()可以在dog和cat中可以直接用,但是并不是这样的,它只是在Animal类中加入了下面的代码

 public virtual string Shout()
            {
                return "";
            }

而在dog和cat类中加入override关键字。

 public override  string Shout() 

其他代码部分基本相同,dog和cat在继承Animal类时还是要重写shout()方法,并没有解决上面的问题(这个问题将在重构中解决)这样并没有体现写的代码少了的优势,相反的还多写了几行代码,不知道有什么优势。要深刻理解多态的好处,还要多多研究设计模式。要非得说有什么用,我想多态的作用就是实例化类时更方便一些吧。所以有了书上的例子,增加一个“动物报名”的按钮,多几个小猫小狗来报名,再增加一个“叫声比赛“的按钮这样这些小猫小狗在使用shout()方法时就会更方便一些吧。

如下面的例子


 private Animal[] arrayAnimal;
        //声明一个动物数组
        //“动物报名”的按钮事件
        private void button3_Click(object sender, EventArgs e)
        {
            arrayAnimal = new Animal[5];//实例化最多可报名5个的动物数组对象
            arrayAnimal[0] = new Cat("小花");
            arrayAnimal[1] = new Dog("阿毛");
            arrayAnimal[2] = new Dog("小黑");
            arrayAnimal[3] = new Cat("娇娇");
            arrayAnimal[4] = new Cat("咪咪");//报名的分别是猫、狗、狗、猫、猫
        }
        //“叫声比赛“的按钮事件
        private void button4_Click(object sender, EventArgs e)
        {
            foreach (Animal item in arrayAnimal)//遍历这个数组,让它们都Shout()
            {
                MessageBox.Show(item.Shout());//由于有了多态性,所以叫的时候,程序会自动去找item是什么对象,然后用那个重写方法
            }
        }
运行结果


三、重构

在多态中是加了virtual虚拟方法和override方法的重写,但是并没有实现像上面说的将cat和dog中重复的方法写到animal中。我想重构就像是字面说的,重新架构我们的代码,也许第一遍写代码时需要的功能已经能实现,但是会有很多冗余和缺陷,通过重构,使我们的代码得到优化。

优化后,可以将shout()方法写入Animal类中,在animal类中加入下面的代码

 public  string Shout()//去掉Virtual,成为普通的公共方法
            {
                string result = "";
                for (int i = 0; i < shoutNum; i++) ;
                result += getShoutSound() + ", ";
                //此处是原先子类的唯一不同之处,所以改成调用一个虚方法getShoutSound

                return "我的名字叫" + name +"" + result ;
            }
            protected virtual string getShoutSound()//"得到叫声",虚方法,让子类重写,只需给继承的子类使用,所以用protected修饰符
            {
                return "";
            }

那么子类就非常简单了,所有重复都转移到了父类!

class Cat : Animal //继承格式是子类:父类
        {
            public Cat()
                : base()     //子类构造方法需要调用父类同样参数类型的构造方法,用base关键字代表父类
            { }
            public Cat(string name)
                : base(name)
            { }
            protected override string getShoutSound()//重写getShoutSound()方法
            {
                return "喵";
            }
        }

总之:面向对象就是为了实现让我们的代码更加优化。






猜你喜欢

转载自blog.csdn.net/u013034828/article/details/41788461
今日推荐