3.8 继承

  在类的设计中,经常需要管理和开发相似功能。在设计这些类的时候,就可以使用继承的原则。在面向对象的应用程序开发中,允许创建一个抽象的类而不实现其具体方法,而需要通过继承、派生来实现方法。这样不仅优化了代码,提高了代码的可读性,而且在开发过程中,也让开发人员有比较明确的编码思想,使开发人员与开发人员之间更加容易协调。

3.8.1 继承的基本概念
  在应用程序开发过程中,需要完成功能相近但是实现不同的类来抽象对象的时候,就需要用到继承。例如,要开发一个应用程序或者网站来统计全球动物的种类和基本信息的时候,就需要创建一些类,比如人类、猫、狗等等。相比之下,人类和猫和狗有相似之处,如它们都是哺乳动物,说的更高一点,就都是生物。而人,猫和狗却是不同的对象,还必须要区分三者之间的关系,错误的类设计代码如下所示。
+展开
-C#
    public class Animal//编写类
    {
        public string type;//动物的种类
        public string color;//动物的颜色
        public string sound;//动物叫的声音
    }
    class Program//应用程序主类
    {
        static void Main(string[] args)//应用程序入口方法
        {
            Animal cat = new Animal();//创建对象
            cat.type = "cat";//猫科动物
            cat.sound = "miaomiao";//猫的叫声为miaomiao
            Animal person = new Animal();//创建对象
            person.type = "person";//人类
        }
    }

  上述代码中,并没有语法错误,但是有逻辑误差或者说是开发困难。因为,如果要形容人类的国家,那么就得在Animal类中增加一个country,但是猫却没有国家之分,这样就让整个类变得非常的混乱且庞大臃肿,使用派生就能解决这样的问题。派生类的优点如下所示。
?1)提高重用性:派生提高了代码的重用性,不至于在创建一个新对象时再重新写一个新的类。
?2)提高结构性:派生让程序有了结构,在程序开发过程,每一个派生类均继承上一个类的方法,且每个派生类除了可以使用公共的字段以外,可以专门为派生类增加字段和方法而不去影响到其他的派生类。

  上述代码中可以看出,在设计类的时候,对于同一个类的重复使用,可能会使用户非常的迷惑。例如猫是派生自动物的,但是用户会希望猫的类名是Cat,而同样,当创建一个人的类的时候,通常情况下用Animal描述是不太适合的,虽然人和猫都是属于动物,但是这样的表述往往让人迷惑不解,而派生类可以更好的实现。

3.8.2 创建派生类
  通过使用派生类,可以让程序的代码的意义更加的明确和容易阅读,可以通过改造派生类去实现更多的方法,而不用修改基类,以免影响到其他的派生类。在.NET中,当创建一个应用程序或者是Web Form应用程序时,其实都已经默认派生自一个系统提供的基类。而派生可以允许派生用户自定义的类,示例代码如下所示。
+展开
-C#
    public class Animal//创建基类
    {
        public string type;//创建基类成员
        public string color;//创建基类成员
        public string sound;//创建基类成员
    }
    public class People:Animal//创建派生类
    {
        public string country;//创建派生类成员
    }

  使用“:”运算符说明该类是派生自一个基类,上述代码创建了一个新的类Person来描述人类这种高级动物,“:”运算符说明了People类派生自Animal。

  创建了派生类,说明了该派生类继承了基类的共有或保护的方法和属性,在派生类中可以无需在声明变量。例如上述代码中,为People类增加了country字段来描述人类的国家。而人类同样有声音、肤色等,这些基类已经提供,就可以不需要再重新声明了,可以直接通过“.”运算符使用,因为基类的字段或方法已经被“继承”了,示例代码如下所示。
+展开
-C#
    public class Animal//创建基类
    {
        public string type;//创建基类成员
        public string color;//创建基类成员
        public string sound;//创建基类成员
    }
    public class People:Animal//创建派生类
    {
        public string country;//创建派生类成员
    }
    class Program
    {
        static void Main(string[] args)
        {
            People person = new People();//创建派生类对象
            person.country = "China";//初始化派生类字段
            person.color = "yellow";//使用基类字段
        }
    }

  上述代码中,People类并没有声明字段color,但是People类是继承自Animal类的,而Animal类包括字段color,并且该字段是共有的,所以在People类中也可以使用color。

注意:当基类的字段或者方法等访问修饰符为public或protected时,继承的派生类可以使用基类的字段或方法。但是当基类的字符按或方法等访问修饰符为private时,继承的派生类不能使用基类的private字段或方法。

3.8.3 对象的创建
  当创建一个派生类的对象,派生类的对象可以使用基类中共有(public)或保护(private)的类成员。之所以派生类的对象能够使用基类的类成员,是因为在创建派生类的对象的时候,首先会执行基类的构造函数,然后再执行派生类的构造函数,最后一个对象才会被创建,示例代码如下所示。
+展开
-C#
    public class Animal//编写类
    {
        public Animal()//编写构造函数
        {
            Console.WriteLine("Animal被构造");//Animal构造函数
        }
    }
    public class People:Animal//编写派生类
    {
        public string country;//声明变量
        public People()//编写构造函数
        {
            Console.WriteLine("People被构造");//People构造函数
        }
    }
    class Program//应用程序主类
    {
        static void Main(string[] args)//创建主方法
        {
            People person = new People();//创建一个Person对象
            Console.ReadKey();//等待用户按键
        }
    }

运行结果如图3-5所示。
派生类的构造
图3-5 派生类的构造
  从上述代码中可以看出,当创建了Person类的对象的时候,虽然没有创建Animal类的对象,但是还是构造了Animal类。Animal的构造函数执行后,才开始执行Person的构造函数。当执行了Person构造函数,势必会执行Person基类的构造函数,如果一个派生类的基类有多个构造函数,而开发人员想指定构造函数时,必须使用base关键字,Animal类示例代码如下所示。
+展开
-C#
    public class Animal//编写类
    {
        public Animal()//编写构造函数
        {
            Console.WriteLine("Animal被构造");//构造函数
        }
        public Animal(DateTime time)//另一个构造函数
        {
            Console.WriteLine("Animal在" + DateTime.Now.ToString() + "被构造");//另一个代码块
        }
    }

  上述代码中,Animal类具有两个构造函数,而要让派生类使用基类的某个构造函数,就必须指定派生类使用的基类的构造函数的方法,示例代码如下所示。
+展开
-C#
    public class People:Animal//编写派生类
    {
        public string country;//定义字符串型字段
        public People(DateTime time):base(time)//指定构造函数
        {
            Console.WriteLine("People被构造");//编写构造函数
        }
    }

  在指定了构造函数后,在主函数中也必须修改相应的对象的创建代码,示例代码如下所示。
+展开
-C#
        static void Main(string[] args)//主入口方法
        {
            People person = new People(DateTime.Now);//使用指定的构造函数
            Console.ReadKey();//等待用户按键
        }

运行结果如图3-6所示。
指定使用基类的构造函数
图3-6 指定使用基类的构造函数

3.8.4 使用抽象类
在类被创建的时候,派生类的构造函数在执行前,会首先执行基类的构造函数。当声明或者设计一个类的结构时,基类往往是不完善的,也不应该把基类的类成员实例化。直接从Animal类创建对象是不正确的,因为基类的作用是为了整合派生类中公共的相同或相似的属性或字段,而对基类的成员赋值或者创建基类的对象,会使类的结构变得混乱。

例如在上面的例子中,Person类从Animal类派生,当开发人员希望创建一个对象的时候,无论是从代码还是命名都能够更好的理解。虽然很多场景会不会使用人类的国家参数,但是从Person类创建对象还是比从Animal类创建对象更加好理解,示例代码如下所示。
+展开
-C#
            People abc = new People();//创建对象
            Animal abcd = new Animal();//创建对象

从上述代码中,阅读代码时,能够非常清楚的了解abc是一个人,而不是一只猫或者一只狗。而abcd却让人匪夷所思,只知道此对象是动物,而不知道具体是什么。虽然上述的例子中,abc没有任何意义,在这里只是使用了开发中的某个场景,当代码过长的时候,命名也会变得困难,也会很难找到合适的命名,但是还是推荐使用有意义的名称来定义变量,例如person。这里只是作为例子来说明创建对象时,好的类设计带来的好处。

创建对象时,如果对基类使用abstract关键字,那么编译器会阻止基类的直接实例化,从而可以强制的让开发人员使用正确的类让类层次结构正确并容易阅读。当用户创建Animal bird=new Animal()时,编译器会报错并提示错误,示例代码如下所示。
+展开
-C#
    public abstract class Animal //创建抽象类
    {
        public Animal()//创建构造函数
        {
            Console.WriteLine("Animal被构造");//编写构造函数
        }
    }

当使用上述代码进行类的对象的创建时,系统会提示错误,因为该类是一个抽象类,在抽象类的基类中,系统是禁止基类的直接实例化的。

3.8.5 使用密封类
与抽象类相反的是,C#支持创建密封类,密封类是一种永远不能做基类的类。其他的类不能从此类派生,从而保证了密封类的密封性和安全性,使用sealed关键字能够创建密封类,示例代码如下所示。
+展开
-C#
    public sealed class Animal//创建密封类
    {
        public Animal()//创建构造函数
        {
            Console.WriteLine("Animal被构造");//编写构造函数
        }
    }

当Person再次从Animal派生时,编译器会提示出现错误,Person类无法从密封类Animal派生。

注意:设计类的时候,通常情况下是不需要将类设置为密封类的,因为密封类会让类的扩展性非常的差,这个类也无法再次扩展和派生。但是,出于某种目的,当程序块只需要完成某些特定的功能或者在商业上为了保密,则可以使用密封类对类进行密封,保证类的可靠性。

加支付宝好友偷能量挖...


评论(0)网络
阅读(206)喜欢(0)Asp.Net/C#/WCF