要开始大话设计模式的学习了,看这本书的封面,感觉很轻松,很卡通,很有趣。一本新书怎么去读,怎么去学,老师讲过很多次了。
一本书的前言是相当重要,它能帮助我们掌握全局,它也可能会给予我们一些指导。读完前言,我便知道自己下一步该做什么了。
下一个脚步——面向对象再理解。
关于面向对象,在学习C#的时候有了初步总结,但感觉很多概念理解得都不是很深刻。所以,在学习设计模式之初,很有必要再次进行总结。
从设计模式这本书中,故事性、提问性、交谈性的编写方式,读起来的感觉真的不太一样,没有那么枯燥,硬邦邦的感觉。
什么是对象?什么是类?就从动物运动会这个故事的开端说起了。
怎么才能实现猫叫?这个问题对于我们来说很容易啊,只要在点击按钮的事件下添加一行代码就可以了,
<span style="font-size:24px;"><span style="font-family:KaiTi_GB2312;font-size:18px;">private void button1_Click(object sender, EventArgs e) { MessageBox .Show ("喵"); } </span></span>但这样做,很多问题就出现了。如果在其他事件下也需要实现猫叫,怎么办呢?这就引出了“类”,有了类,我们可以随时随地调用它。
<span style="font-size:24px;"><span style="font-family:KaiTi_GB2312;font-size:18px;">class Cat//定义猫类 { public string Shout()//类的方法 { return "喵"; }</span></span>我们该怎么去应用类呢?答案是将类实例化,这就引出了“对象”。接下来一个实例就是声明一个cat对象,让其实现猫叫。
<span style="font-size:24px;"><span style="font-family:KaiTi_GB2312;font-size:18px;">private void button1_Click(object sender, EventArgs e) { Cat cat = new Cat();//类实例化 MessageBox.Show(cat.Shout()); }</span></span>什么是构造函数?什么是方法重载?我们的故事才刚刚开始。
人出生了,爸妈都会想着给孩子起个名字。动物也一样,特别是家里养得宠物,都有个可爱又洋气的名字。那么这就要用到构造函数了,即对类初始化。
所有的类都有构造方法,且与类同名,如果不定义构造方法,系统会默认生成空的构造方法。我们要给猫起个名字,就需要自己写一个构造方法。
<span style="font-size:24px;"><pre name="code" class="csharp"><span style="font-family:KaiTi_GB2312;font-size:18px;">class Cat//定义猫类 { private string name = "";//声明Cat类的私有字符串变量name public Cat(string name)//定义Cat类的构造方法,参数为输入一个字符串 { this.name = name; } public string Shout()//类的方法 { return "我的名字叫" + name + " 喵"; } }</span></span>
<span style="font-size:24px;"><span style="font-family:KaiTi_GB2312;font-size:18px;">private void button1_Click(object sender, EventArgs e) { Cat cat = new Cat("咪咪"); MessageBox.Show(cat.Shout()); }</span></span>这样我们就可以实现给猫起个名字叫“咪咪”。另外,一个类中构造函数的个数是可以多个的,可以根据需要删减,比如:我们也可以添加猫的出生日期等等。
但有时候,名字一开始还没有确定,这样不给出一个名字,就会出错了。这里我们就可以用重载的方法解决。同一个方法名,但参数类型不一样。这也验证了我的上一个说法,构造函数可以多个,下面,为了避免错误的法伤,我们又添加了一个构造函数:
<span style="font-size:24px;"><span style="font-family:KaiTi_GB2312;font-size:18px;">class Cat//定义猫类 { private string name = "";//声明Cat类的私有字符串变量name public Cat(string name)//定义Cat类的构造方法,参数为输入一个字符串 { this.name = name; } public Cat()//构造函数重载 { this.name="无名"; } public string Shout()//类的方法 { return "我的名字叫" + name + " 喵"; } }</span></span>
故事仍在继续,下面是讲讲属性与修饰符的故事。
每个人,都有自己的身高、体重等,这就是对象的属性。以前写代码,写个对象“.”后面就会出现很多,其中就有各种属性。现在在类里面写属性了,感觉非常不一样。现在就以
“猫叫的次数”属性为例。
<span style="font-size:24px;"><span style="font-family:KaiTi_GB2312;font-size:18px;"> private int shoutNum = 3;//声明默认叫的次数为3 public int ShoutNum { get { return shoutNum;//读属性 } set { shoutNum = value;//写属性 } }</span></span>
改进叫的方法:
<span style="font-size:24px;"><span style="font-family:KaiTi_GB2312;font-size:18px;"> public string Shout()//类的方法 { string result = ""; for (int i = 0; i < shoutNum; i++) { result += "喵 "; } return "我的名字叫:" + name + "喵 " + result; }</span></span>
<span style="font-size:24px;"><span style="font-family:KaiTi_GB2312;font-size:18px;">private void button1_Click(object sender, EventArgs e) { Cat cat = new Cat("小咪");//实例化一个小咪对象 cat.ShoutNum = 5;//给属性赋值 MessageBox .Show (cat.Shout()); }</span></span>
结果:
public和private都是修饰符,用以前的话说就是两者的作用域不同。现在具体来说,public表示它所修饰的类成员允许其他任何类访问,也就是公有的;private只允许同一个类
中的成员访问,也就是私有的。
故事的开端好像有点长啊,不过这都是需要一步步慢慢来,一个个小故事慢慢讲,别着急,接下来,就是故事的高潮了,即面向对象的三大特性:封装、继承和多态。
先来说说封装的好处:可以减少耦合;类内部的实现可以自由修改;这一点,在敲机房系统的时候,有些体会。实现某个功能,把它写在模块中,在需要用的地方调用就好了,
这就是封装的好处,减少了不少代码。我们实现了猫叫,那怎样实现狗叫呢?
现在这个工作就简单多了,仿造Cat类加一个Dog类,并添加相应的事件。
结果:
这样下来,又会发现,其中为了实现它们,其中还是包含很多重复的代码。我们又该如何去解决呢?这就需要讲到第二个特性继承了。
先从类的角度来说,猫和狗都是属于同一类,即哺乳动物。也可以换句话说,猫和狗与哺乳动物间属于继承关系。
下面给大家讲讲继承的工作方式:
定义父类(基类)和子类(派生类),其中子类继承父类的所有特性,同时也可以有自己新的特性。
学习继承需要记住的三句话:
如果子类继承与父类,那么
1.子类拥有父类非Private的属性和方法;
2.子类可以有自己的属性和方法;
3.子类可以以自己的方式实现父类的方法(方法重写)。
继承的格式:子类:父类,可用base关键字代表父类。
先对比上面写的Dog类和Cat类,可以发现,除了画线的那些地方,其他代码都是一样的:
下面就还以上面的例子,加上继承的思想重新编写代码。
先建立一个父类:Animal
<span style="font-size:24px;"><span style="font-family:KaiTi_GB2312;font-size:18px;">class Animal//定义动物类 { protected string name = ""; protected Animal(string name) { this.name = name; } public Animal () { this.name = "无名"; } protected int shoutNum = 3; public int ShoutNum { get { return shoutNum; } set { shoutNum = value; } } }</span></span>
下面写Cat的代码,
<span style="font-size:24px;"><span style="font-family:KaiTi_GB2312;font-size:18px;">class Cat : Animal { public Cat() : base() { } public Cat(string name):base(name) {} public string Shout() { string result = ""; for (int i = 0; i < shoutNum; i++) result += "喵, "; return "我的名字叫" + name + " " + result; } }</span></span>
Dog代码与之类似,把名称改了就行。
结果:
这样的话代码又简单了不少。下面接着讲第三个特性:多态。
这一次举的是“动物报名”和“叫声比赛”的例子。动物来了,它们就报上自己名字并发出自己的声音。如何去实现呢?
现在父类不上场了,就完全由子类自己去实现,但子类必须完全按照父类的方法去实现,这就需要为父类加“virtual”关键字,为子类加“override”关键字。
那除了猫和狗,要是其它动物来了,它们又该怎么办呢?比如说牛和羊。一想,只要再多加两个类就行了,并让它们
继承父类Animal。可是,这样,代码又多了许多。这就需要讲讲重构了。我们就需要修改Shout方法,针对不同的动
物,让它们自己返回不同的声音,这个新方法叫getShoutSound方法,这一过程就是重构了。
<span style="font-size:24px;">public string Shout() { string result = ""; for (int i=0;i<shoutNum ;i++) result +=getShoutSound()+ ", "; return "我的名字叫" + name + " "+result ; }</span>
接下来是不同的子类,返回值各不相同,如狗类和羊类:
<span style="font-size:24px;">class Sheep : Animal { public Sheep() : base() { } public Sheep(string name) : base(name) { } protected override string getShoutSound() { return "咩"; } }</span>
<span style="font-size:24px;">class Dog : Animal { public Dog() : base() { } public Dog(string name) : base(name) { } protected override string getShoutSound() { return "汪"; } }</span>
故事的刚开始我们就谈了类,现在故事快接近尾声了,经过了前面那么多的实例,抽象类这个概念就更加容易理解
了。之前我们定义了很多类,动物这个父类,猫、羊等子类,我们可以想象出一只猫的样子,可动物的样子是无法确
定的,也就是无法对其进行实例化,所以它就是一个抽象类了,用关键字abstract表示。
什么是接口?它和抽象类有什么区别?接下来继续我们的故事。
说起铃铛猫和孙悟空,它们都有特异功能,会变东西。但两者是因为情况并不相同,叮当猫是因为有口袋,孙悟空是
因为七十二变,要它们一起实现变出东西,就需要一个接口去帮助它们。所以,首先声明个接口:
<span style="font-size:24px;">interface IChange { string ChangeThing(string thing); }</span>
然后机器猫通过接口实现变东西:
<span style="font-size:24px;">class MachineCat : Cat, IChange { public MachineCat() : base() { } public MachineCat(string name) : base(name) { } public string changeThing(string thing) { return base.Shout() + " 我有万能的口袋,我可变出: " + thing; } }</span>
抽象类和接口的区别:
1.抽象类是对类的抽象;
2.行为跨越不同类的对象,可使用接口;对于一些相似的对象,可用继承抽象类。
下面同样是讲两者的区别,一个是数组,一个是集合:
它们主要是容量区别,数组是固定的,而集合可根据需要自动扩充。
故事讲了很久,很累了,这么一看,又把面向对象以故事的方式又温习了一遍,可能对于某些东西还不是理解得很透
彻,还需要日后多多体会才行。通过这些故事,通过故事中实例的实现,比起之前结合C#视频的总结,还是有所进步
的。面向对象,以后还需要把你温习。
最后附上一张学习过后自己重新回想知识整理的一些概念: