背景:
《大话设计模式》最后的面向对象基础,介绍了很多基础性的知识。例如继承,多态,接口,抽象类等。学习过后有了一些自己的总结,于是就有了这篇博客。
猛一提起,接口和抽象类,大家也许模模糊糊有个印象,但是具体它们二者有什么区别,还是说不上来。
所以,为了更好的了解和区分二者,更好的在程序代码中应用。我们下面来看看,接口和抽象类,到底有什么区别。
抽象类:
举个栗子:
小狗,小猫,小猪都是小动物,这些可爱的动物们都会发出叫声,小狗是“汪汪汪”,小猫是“喵喵喵”,小猪是“哼哼哼”。
现在,要我们实例化一个小狗,我们可以想象到小狗的样子,也许是其二无比的哈士奇,也许是微笑天使萨摩耶,总之实例化小狗是没问题的。
但是要我们实例一个小动物,我们不知道这小动物是什么样子,就没有办法实例化“动物”。因为动物是一个抽象的名词,所以,我们完全可以考虑把实例化没有任何意义的父类,改成抽象类。再来想,小狗小猫的叫声方法是具体的,但是动物的叫声是挺抽象的,是没有意义的,所以动物的叫声,可以改为抽象方法。
在 C#中,允许把类和方法声明为abstract,(abstract就是抽象的意思)即抽象类和抽象方法。
代码表示:
<span style="font-family:Comic Sans MS;font-size:18px;"> abstract class Animal
{
……
Protected abstract string getShoutSound();
}
</span>
特点:
1.抽象类不能被实例化。(实例化动物,没有意义)
2.抽象方法必须要被子类重写的,不被重写,抽象方法就没有意义啦。
3.如果一个类里存在抽象方法,无论这个类里是否还存在其它一般的方法,这个类必须得是抽象类。(扣上抽象方法的帽子,这个类必然定义为抽象类)
上面的抽象类,希望我解释的不那么抽象,下面我们继续看看“接口”的相关知识。
接口:
举个栗子:话说,元宵节了,小动物们元宵喜乐会,大家show各自的才艺的时候到了。
本命年的孙悟空孙大圣,他带来的节目是《大圣归来2——看我72变》;特地从任意门赶来的小叮当,带来的节目是《口袋魔术》;没有睡懒觉,从高老庄坐高铁早早来到的猪八戒,带来的节目是《猪猪侠的36计》。
这些拥有魔法可以变东西,技高一筹的动物们,掌握的可不止是普通动物“叫声”的技能了,普通动物是没有办法具备他们三只的特异功能的,也只有它们三只拥有变东西的方法,这些特定的方法封装成为一个集合,就是我们要了解的接口(interface)了。
来一张UML图,帮你更好理清关系。
因为,接口封装的是特殊功能,所以接口就像“高冷挑剔”的公主。又一下特性:比如,接口不可以实例化,要实现接口的类,就必须实现接口里所有的方法和属性。
但是别看接口挑剔,她也有“善解人意、热心肠“的一面,因为一个类可以实现多个接口,多个类也可以支持相同的接口。因为,接口让用户和其它开发人员更容易理解其他人的代码,接口让代码充满了爱,所以”充满爱“的接口有一个命名标志——大写的“I”。大家使用接口的时候,不要忘记哦。
部分代码理解展示:
变东西接口代码表示:
<span style="font-family:Comic Sans MS;font-size:18px;"><span style="font-family:Comic Sans MS;font-size:18px;"> Interface IChange //声明IChange 接口,记得”I“
{
String ChangeThing(string thing); //接口的方法ChangeThing,括号里的参数是一个字符串变量,返回值类型也是字符串
}</span></span>
叮当猫类代码表示:(Cat类代码不再展示,大家可以自由发挥)
<<span style="font-family:Comic Sans MS;font-size:18px;">span style="font-family:Comic Sans MS;font-size:18px;"><span style="font-family:Microsoft YaHei UI;font-size: 16pt;"> </span><span style="font-family:Comic Sans MS;"><span style="font-size: 16pt;">class MachineCat:Cat,Ichange//</span><span style="font-size:24px;">叮当猫继承猫类,并且实现IChange接口。</span><span style="font-size: 16pt;">
{
public MachineCat()
:base()
{
}
public MachineCat(string name)
:base(name)
{
}
public string ChangeThing(string thing) //实现接口方法
{
return base.Shout()+"我有万能的魔法口袋,我可以变出:"+ thing;
}
}</span></span><span style="font-family:Microsoft YaHei UI;font-size: 16pt;">
</span></span></span>
孙大圣和猴子类也不再展示,大家自行发挥~
客户端代码表示:
<span style="font-family:Comic Sans MS;font-size:18px;"><span style="font-family:Comic Sans MS;font-size:18px;"><pre name="code" class="csharp"><span style="font-size:24px;"><span style="font-family:Comic Sans MS;">Private void button2_Click(object sender,EventArgs e)
{
MachineCat mcat= new MachineCat("叮当"); //创建两个类的实例
MonekyKing wukong=new Mokeyking("孙悟空");
Ichange[] array =new Ichange[2]; //声明一个接口数组,分别将两类的实例赋值给数组。
array[0]=mcat;
array[1]=wukong;
MessageBox.Show(array[0].ChangeThing("各种各样的东西!")); //利用了面向对象的多态性,实现各自的ChangeThing
MessageBox.Show(array[0].ChangeThing("五花八门的东西!"));
}</span>
</span></span></span>
运行结果:
点击"叮当"按钮,显示:我的名字叫叮当,喵喵喵,我有万能的口袋,我可变出各种各样的东西!
点解"孙悟空"按钮,显示:我的名字叫"孙悟空",吼吼吼,我会七十二变,我可变出五花八门的东西!
对比分析:
分别了解完抽象类和接口,我们最后来一个小总结,对比分析一下抽象类和接口。
从形态上来看:一个类只能继承一个抽象类,但是一个类可以实现多个接口。
抽象类 | 接口 |
类整体的抽象 | 类局部行为的抽象(如果只关注行为抽象,接口也是抽象类) |
继承抽象类,应用于相似的类(猫狗继承动物类) | 行为跨越不同的类(飞机麻雀 超人都会飞,但是各属不同的类)接口和继承抽象类不冲突(超人继承人类,实现飞行的接口) |
自底向上抽象,重构而来(猫狗公共特征泛化出父类动物) | 自顶向下设计,对方法实现未知(对于动物们如何实现特异功能行为未知) |
全文总结:
通过可爱的小动物了解抽象类和接口,我们会发现其实面向对象充满了乐趣,面向对象应用在我们的生活当中,用心观察生活,认真生活,我们会找到和面向对象更多更有趣的联系。PS:今天是元宵节,祝大家节日快乐~
以上若有失误之处,望各路豪杰提点~