C#入门详解(13)
为做基类而生的基类和开放/关闭原则
有上节继承开始引导,上代码
public class Program { static void Main(string[] args) { Vehicle vehicle = new Car(); vehicle.Stopped(); } } public class Vehicle { public void Stopped() { Console.WriteLine("Stop it"); } } class Car : Vehicle { public void Run() { Console.WriteLine("B"); } } class RaceCar :Vehicle { public void Run() { Console.WriteLine("C"); } }
在代码中我们的vehicle实例只有stopped方法,而无法调用car里面的run方法,为了解决这个问题,我们有两种解决方案:
虚方法:
public class Program { static void Main(string[] args) { Vehicle vehicle = new Car(); vehicle.Run(); Vehicle vehicle_ = new RaceCar(); vehicle_.Run(); } } public class Vehicle { public void Stopped() { Console.WriteLine("Stop it"); } public virtual void Run() { Console.WriteLine("..."); } } class Car : Vehicle { public override void Run() { Console.WriteLine("B"); } } class RaceCar :Vehicle { public override void Run() { Console.WriteLine("C"); } }
在基类中添加虚方法,让子类去重写,可有效解决这个问题。
在Vehicle加方法:
public class Vehicle { public void Stopped() { Console.WriteLine("Stop it"); } public void Run(string typename) { if (typename=="Car") { Console.WriteLine("B"); } else if (typename == "RaceCar") { Console.WriteLine("C"); } } }
违反了开闭原则,我们更改的类是关闭的,这个方法不行。
在上面两个方法中,我们采用虚方法这个解决方案,但不难发现,在实际工作中,我们可能永远不会调用Vehicle里面的Run方法,所以我们可以给他变成纯虚方法,使用关键字abstract,相应的类也变成了抽象类。
public abstract class Vehicle { public void Stopped() { Console.WriteLine("Stop it"); } public abstract void Run(); }
当Vehicle里面的方法都为虚方法,它就是纯抽象类,这在C++比较常见,在C#中就是Interface,命名一般也以I开头
什么是接口和抽象类
接口和抽象类都是软件工程的产物
具体类-抽象类-接口:越来越抽象,内部实现的东西越来越少
抽象类是未完全实现的类,接口是完全未实现的类(可以有实现与未实现的成员和非public成员,它们代表了具体逻辑)
抽象类为复用而生:专门作为基类来使用,也具有解耦功能
封装确定的,开放不确定的,推迟到子类中实现
接口是完全未实现逻辑的“类”(纯虚类:只有函数成员;成员全部public)
接口为解耦而生:高内聚低耦合方便单元测试
接口是一个协约,早已为工业生产所熟知,有分工必有协作,有协作必有协约
它们都不能实例化,只能用来声明变量,引用具体类(concrete class)的实例