C#读书笔记之继承、接口与抽象类

  最近正在读《C#与.NET3.5高级程序设计第四版》,写的挺不错的一本书。以前理解比较模糊的继承、接口、抽象类都有了更深一步的理解。现在写下一些自己最近的理解,第一为了加深印象,第二为了和其他跟我一样正处在起步学习阶段的朋友一起分享经验,第三则是为了能够得到大家的帮助,帮我纠正其中的错误。

  先说接口与抽象类。由于缺少开发经验,一直以来我都很难理解为何要用接口和抽象类。接口与抽象类是各面试题的热门,关于它们的概念死记硬背都能背下来。但是,仅仅明白定义是没用的,想要真正理解一个概念,最基本的就是要理解为什么要定义这么一个概念,即,为什么要定义接口和抽象类。

  最能帮助理解的方式就是使用例子。要想讲接口和抽象类必须从继承开始讲起,所以先举下面这个比较粗糙的例子说明一下继承。

1.继承

  有一家卖家电的小铺(myShop),出售各种家电(electronics),这家商铺要做的事情就是卖家电(Sell)。假设有两种家电,电视机(television)和电冰箱(fridge)。我们需要做的就是出售这两种家电。下面是出售家电的代码:

  

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Blog1
{
    class Program
    {
        static void Main(string[] args)
        {
            Shop myShop = new Shop();
            Television tels = new Television();
            tels.Count = 100;
            Fridge fris = new Fridge();
            fris.Count = 100;
            myShop.SellTelevision(tels, 20);
            myShop.SellFridge(fris, 20);
        }
    }
    class Television
    {
        //数量
        public int Count { get; set; }
    }
    class Fridge
    {
        //数量
        public int Count { get; set; }
    }
    class Shop
    {
        /// <summary>
        /// 出售电视机
        /// </summary>
        /// <param name="tel">电视机对象</param>
        /// <param name="num">卖出数量</param>
        /// <returns>剩余数量</returns>
        public int SellTelevision(Television tel, int num)
        {
            return tel.Count - num;
        }
        public int SellFridge(Fridge fri, int num)
        {
            return fri.Count - num;
        }
    }
}

 

   看了类定义,我们很容易就能发现,这里的电视机和电冰箱非常相似,可以说仅仅是名字不同罢了。联系现实,我们知道电冰箱和电视机都属于家电类,于是我们可以写一个父类Electronics,让电冰箱和电视机继承该类,将代码改为如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Blog1
{
    class Program
    {
        static void Main(string[] args)
        {
            Shop myShop = new Shop();
            Television tels = new Television();
            tels.Count = 100;
            Fridge fris = new Fridge();
            fris.Count = 100;
            myShop.SellElectronics(tels, 20);
            myShop.SellElectronics(fris, 20);
        }
    }
    class Electronics
    {
        public int Count { get; set; }
    }
    class Television : Electronics
    {    
    }
    class Fridge : Electronics
    {
    }
    class Shop
    {
        /// <summary>
        /// 出售家电
        /// </summary>
        /// <param name="tel">家电对象</param>
        /// <param name="num">卖出数量</param>
        /// <returns>剩余数量</returns>
        public int SellElectronics(Electronics ele, int num)
        {
            return tel.Count - num;
        }
    }
}

仔细观察,我们能发现两点不同之处:

1.Television类里和Fridge类里没有任何定义。

2.Shop类里的两个方法SellTelevison(Televison tel,int num)和SellFridge(Fridge tel,int num)变成了一个方法SellElectronics(Electronics ele,int num). 

这是继承基本的功能,关于为何会形成这种情况可以看继承的定义。回到开头提出的问题,这里说说这么做有什么用。

我们知道,当我们执行Shop的Sell***功能时,需要传入一个对象表示你要出售的是什么,在不使用继承的代码中,我们需要设定两个方法来分别执行两种商品的出售功能。当商品只有两种时,这当然没有问题,但是,设想一下,真正的家电商铺是不可能只卖两种商品的,假如我们有二十种商品,就需要写二十种Sell***方法。而且,更糟糕的是,假如我们的商铺在原来的基础上又增加了一种新的商品,我们就需要修改Shop这个类以添加相应的Sell***方法。这个时候我们就会想,可不可以用一个方式,将这些相似的东西统一起来呢?

于是我们使用了继承。

来看看前面说的两点不同吧。

1.Television类里和Fridge类里没有任何定义。

这是继承的第一个功能。我们定义了一个表示家电的类Electronics,里面定义了一个属性Count,然后让Television类和Fridge类继承了Electronics。这等于是告诉程序:电视机和电冰箱都是家电,家电该有的特征它们也应该有。所以,在后面实例化后的tels和fris可以直接使用Count属性。这有什么作用呢?

①统一,这使得所有继承于Electronics的类都有了Count这个属性。这是很重要的一点,接下去会说明。

②减少了代码量。我们可以在Electronics里定义各种属性与方法,比方说,家电的价格Price,家电通电的方法Power(),然后我们当我们的商铺拥有几十种商品时,就可以让这几十种商品的类继承这个Electronics类,它们就不必在内部重新写这些重复的代码了。但是,必须要记住的是,这个家电的属性必须是其派生类(即要继承它的类)所共有的。如果我们给家电定义了一个方法表示发光Shine(),那么我们的电冰箱就无法继承它。

2.Shop类里的两个方法SellTelevison(Televison tel,int num)和SellFridge(Fridge tel,int num)变成了一个方法SellElectronics(Electronics ele,int num)。

这便是继承的另外一个作用了。我们把“卖冰箱”和“卖电视机”两个方法统一成了”卖家电",传进去的是一个Electronics类型的参数。在实际使用中,我们可以直接把Televison类型和Fridge类型的参数传入SellElectronics(Electronics ele,int num)中,这是因为,如果两个类是利用继承关系关联的,那么在基类引用中保存派生类型总是安全的。像Electronics ele=new Fridge()这种写法就是合法的,ele保存了一个新的Fridege类型的对象,这也完全符合我们的现实规律:“卖家电”当然包括“卖电冰箱”。

我们再回到前面说的继承的“统一”功能。我们知道,由于Fridge和Televison都继承了Electronics ,于是它们都有了Count属性。这是强制性的。在我们的SellElectronics()方法中,我们必须用到参数ele的Count属性,正因为这种强制性,保证了我们传进去的Fridge类型参数和Televison类型参数也拥有Count属性,保证了SellElectronics()方法可以正常运行。

关于继承的作用差不多说完了,现在说一下其他的。很多像我这样的初学者会都会遇到一个问题:我学会了继承,接口,抽象类,委托,事件等等一堆新鲜的概念,但是我总是找不到使用它们的地方。为什么会这样呢?首先是经验少,经验少导致我们的思路不够扩展,写代码喜欢循规蹈矩,按自己熟悉的方向来。其次是思考的不够多,宁可敲重复的代码也不愿意去思考能‘偷懒’的方法,做‘思想’上的懒人而不是‘行动’上的懒人。如何克服?我的做法是去修改自己以前写过的代码。做开发是一件很有成就感的事情,当我学了新知识,并且把新知识利用起来时,我也觉得很有成就感。我曾花了几天闲暇时间把自己做过的一项目进行重构,代码量缩少到了一半,在这过程中,有意识的利用一些自己不太熟练地新概念,令我对它们都有了更深的理解,当然,这从侧面反映了我以前的编程方式有多么糟糕。

本想一口气把接口和抽象类都写完的,不过看样子篇幅有点长,还是再开一章罢了。写的也都是些比较基础和简单的概念,意不在教育,旨在能与他人分享。

C#读书笔记之继承、接口与抽象类续  http://www.cnblogs.com/linjzong/articles/2717956.html

posted @ 2012-10-10 09:27  林J  阅读(250)  评论(0编辑  收藏  举报