1500字范文,内容丰富有趣,写作好帮手!
1500字范文 > c#之类 抽象类 接口

c#之类 抽象类 接口

时间:2020-08-21 11:48:10

相关推荐

c#之类 抽象类 接口

最近在看完刘铁猛老师讲解的类,抽象类,接口后,有一种豁然开朗的感觉,现将内容记录下来,以便后续的学习巩固。

先提一下程序设计的六大模式之一的开闭原则(open closed principle):用抽象构建架构,用实现扩展原则;(总纲)

设计模式文章的连接如下:(/luguojiu/article/details/102551573)

在后面的代码重构中会体现这一原则。

一天,小菜与大鸟在一起。

大鸟:小菜,现在有一个项目要交给你。项目要求写一个小汽车,这个汽车具有Run,以及Stop方法,

小菜:很简单呀,看我的。

几分钟后,小菜写出了代码,如下所示:

namespace Example_03{class Program{static void Main(string[] args){}}class Car{public void Run(){Console.WriteLine("Car is running");}public void Stop(){Console.WriteLine("Stopped !");}}}

大鸟:嗯,不错,是这样的。那现在项目中要增加卡车了,和小汽车具有相同的方法。

小菜:简单,我粘贴复制,修改一下就可以了。

很快,代码如下

namespace Example_03{class Program{static void Main(string[] args){}}class Car{public void Run(){Console.WriteLine("Car is running");}public void Stop(){Console.WriteLine("Stopped !");}}class Truck{public void Run(){Console.WriteLine("Truck is running");}public void Stop(){Console.WriteLine("Stopped !");}}}

大鸟:你这样写是没问题的,但是,在代码编写的过程中,尽量不要出现代码的粘贴复制现象。同时,你看看,Car类和Truck类中的方法都是一样的,这样写是不是重复了,还有就是,如果我需要添加更多的车的时候,是不是还需要添加更多的相同代码,这样是比较麻烦的。当多个类中相同代码较多的时候,可以考虑将相同代码放在父类当中

小菜:明白了。

几分钟后:

namespace Example_03{class Program{static void Main(string[] args){//客户端代码(体现了多态)Vechile vh1 = new Car();vh1.Run("Car");vh1.Stop();Vechile vh2 = new Truck();vh2.Run("Truck");vh2.Stop();Console.ReadLine();}}class Vechile{public void Run(string type){if (type=="Car"){Console.WriteLine("Car is running");}else if (type == "Truck"){Console.WriteLine("Truck is running");}}public void Stop(){Console.WriteLine("Stopped !");}}class Car:Vechile{}class Truck:Vechile{}

运行结果:

大鸟:不错。我看到你在基类中改变了Run的方法,以前是不带参数的。

小菜:没办法啊,Car 和Truck的Run方法中的方法体是有区别的。

大鸟:嗯,你这样处理也是可以的。那如果我让你添加一个RaceCar呢?

小菜:我只需要在基类中的Run方法里添加一个else if 的分支,先后写一个RaceCar子类就行了。看我的,

一分钟后,小菜的代码如下:

namespace Example_03{class Program{static void Main(string[] args){//客户端代码(体现了多态)Vechile vh1 = new Car();vh1.Run("Car");vh1.Stop();Vechile vh2 = new Truck();vh2.Run("Truck");vh2.Stop();Console.ReadLine();}}class Vechile{public void Run(string type){if (type=="Car"){Console.WriteLine("Car is running");}else if (type == "Truck"){Console.WriteLine("Truck is running");}else if (type=="RaceCar"){Console.WriteLine("RaceCar is running");}}public void Stop(){Console.WriteLine("Stopped !");}}class Car:Vechile{}class Truck:Vechile{}class RaceCar : Vechile{}}

大鸟:嗯,这样写是可以的。但是,小菜啊,你知不知道你违反了一个程序设计中的一个很重要的原则呀。我先不告诉你,先来说一下存在的问题。按照你的这种写法,如果后续需要添加别的车的时候,你是不是需要频繁的去修改基类Vechile中的代码?

小菜:这个确实是的呀,但是那也没办法啊,有需求了就要改的。如果我想增加属性的话,我不也得去修改这个类啊?

大鸟:没错,如果你需要增加类的属性,确实是需要修改这个类,这个是必然的,同时,如果你需要给类添加新的功能,比如说,车还有加油的功能,那你需要在Vechile中添加Fill函数,这也是需要修改类的,这个也是必然,也是允许的。也就是说,你需要增加类的新功能的时候,修改类是正确的,除此之外,最好不要总去动类中的代码,比如说,增加一种类型的车,你就去修改Run中的方法,这个是不好的。

小菜:我似乎有些明白了。

大鸟:这么说吧,在一个团队了,你负责设计了这个类,然后团队中的另外一个成员需要继承你的这个基类,那么他还得跑到你那边去修改基类的代码,这显然不是好的体验。好的体验应该是,我直接继承,其他的我无需关心。

小菜:懂了。

大鸟:很好,这就是我今天要和你说的设计模式中的开闭原则。你刚刚的代码就是违反了这个设计原则啊。

小菜:那我该如何进行修改呢?

大鸟:首先啊,在设计Run方法时,我们可以考虑将基类的Run方法与子类中的方法具有相同的签名,。。。。

小菜:对,对,然后我将方法设计成虚方法,在子类中进行重写不就可以了嘛;

大鸟:是滴

几分钟后:

小菜改完了代码,如下:

namespace Example_03{class Program{static void Main(string[] args){//客户端代码(体现了多态)Vechile vh1 = new Car();vh1.Run();vh1.Stop();Vechile vh2 = new Truck();vh2.Run();vh2.Stop();Console.ReadLine();}}class Vechile{public virtual void Run(){Console.WriteLine("Vechile is running");}public void Stop(){Console.WriteLine("Stopped !");}}class Car:Vechile{public override void Run(){Console.WriteLine("Car is running");}}class Truck:Vechile{public override void Run(){Console.WriteLine("Truck is running");}}}

运行结果:

大鸟:很好,运行结果与前面一样。在基类中设计虚方法,在子类中进行重写(override)。小菜,你发现没,基类中的虚方法,在实际运行中,一直不会执行到的。

小菜:确实是这样的哈,

大鸟:那这样的话,我们还要他的函数体干啥啊,不如就不要函数实现了啊

小菜:不要函数体了,也就是说函数没有实现,那这个函数就太抽象了。

大鸟:对啊,是很抽象的。这就成了抽象方法了,类也就变成抽象类了。。

小菜:我明白了,我这就去重构代码:

几分钟后:

namespace Example_03{class Program{static void Main(string[] args){//客户端代码(体现了多态)Vechile vh1 = new Car();vh1.Run();vh1.Stop();Vechile vh2 = new Truck();vh2.Run();vh2.Stop();Console.ReadLine();}}abstract class Vechile{public abstract void Run();public void Stop(){Console.WriteLine("Stopped !");}}class Car : Vechile{public override void Run(){Console.WriteLine("Car is running");}}class Truck:Vechile{public override void Run(){Console.WriteLine("Truck is running");}}}

大鸟:嗯,不错,是这样的。从上面 可以看出,只要类包含了抽象方法,那么这个类就是抽象类。当然了,抽象类中还可以包含非抽象方法的。

小菜:嗯,嗯。那如果我把所有的方法都写成抽象函数呢?

大鸟:你可以试一试啊。

小菜:好的。

几分钟后;

namespace Example_03{class Program{static void Main(string[] args){//客户端代码(体现了多态)Vechile vh1 = new Car();vh1.Run();vh1.Stop();Vechile vh2 = new Truck();vh2.Run();vh2.Stop();Console.ReadLine();}}abstract class Vechile{public abstract void Run();public abstract void Stop();}class Car : Vechile{public override void Run(){Console.WriteLine("Car is running");}public override void Stop(){Console.WriteLine(" Car Stopped !");}}class Truck:Vechile{public override void Run(){Console.WriteLine("Truck is running");}public override void Stop(){Console.WriteLine(" Truck Stopped !");}}}

大鸟:对的,是这样的。在之类中,基类中的全部的抽象函数在子类中必须全部实现,一个都不能少。

小菜:那如果我不小心少实了怎么办?

大鸟:这样的话,继承的这个类依然是抽象类。也就是说,一**个类没有完全实现其基类中的抽象方法的话,这个类也是抽象类。**下面,我在你的代码基础上进行修改一下,你看看。

几分钟后,大鸟的代码写好了,看下面:

namespace Example_03{class Program{static void Main(string[] args){//客户端代码(体现了多态)Vechile vh1 = new Car();vh1.Run();vh1.Stop();Vechile vh2 = new Truck();vh2.Run();vh2.Stop();Console.ReadLine();}}abstract class VechileBase{public abstract void Run();}abstract class Vechile:VechileBase{public abstract void Stop();}class Car : Vechile{public override void Run(){Console.WriteLine("Car is running");}public override void Stop(){Console.WriteLine(" Car Stopped !");}}class Truck:Vechile{public override void Run(){Console.WriteLine("Truck is running");}public override void Stop(){Console.WriteLine(" Truck Stopped !");}}}

大鸟:看到了吧,VechileBase是Vechile的 基类,Vechile没有实现VechileBase中的Run方法,因此,Vechile依然是抽象类。但是,最终这些抽象方法都是需要在之类中实现的

小菜:明白了。

大鸟:小菜啊,你看看,在前面你把Vechile这个抽象类中的方法都设计成了抽象方法,这样固然是可以的,但是在实际应用中,我们是不这样做的。这个类的方法全部是抽象的,因此这个类的抽象程度是很高的,这样的话,我们一般用接口。下面我来重构一下代码:

namespace Example_03{class Program{static void Main(string[] args){//客户端代码(体现了多态)IVechile vh1 = new Car();vh1.Run();vh1.Stop();IVechile vh2 = new Truck();vh2.Run();vh2.Stop();Console.ReadLine();}}//abstract class VechileBase//{// public abstract void Run();//}interface IVechile{void Stop();void Run();}class Car : IVechile{public void Run(){Console.WriteLine("Car is running");}public void Stop(){Console.WriteLine(" Car Stopped !");}}class Truck : IVechile{public void Run(){Console.WriteLine("Truck is running"); }public void Stop(){Console.WriteLine(" Truck Stopped !");}}}

大鸟:在接口里,方法也是没有任何实现的。只是定义,没有任何实现。接口只管有什么(what),具体的怎么做(how),接口是不管的接口中只能包含方法,属性,索引器等抽象的东西

小菜:嗯,嗯,终于明白啦。

大鸟:整个的实现过程就是这样的,小菜啊,你一定要理解这些代码在设计之初到最终的重构过程。只有真正理解了,才能在以后的设计过程过程中灵活的应用。

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。