c#基础语言编程-多态

时间:2021-07-24 17:30:09

语言中的多态性是为了使程序有扩展性,为实现多态性,在程序中体现为接口、抽象类、父类、具体类。

接口就是一种规范,解决了多重继承的问题,类似一种规范,告诉我要做什么,具有什么能力,在接口中定义写行为属性。

接口的特性

  1. 接口类类似抽象类,不能实例化接口;接口中的方法都是抽象方法,继承于此接口的非抽象类必须实现接口中所有成员。
  2. 接口只能包含方法(属性、事件、索引器最终都是方法),不能有字段、常量、构造函数和析构函数、静态变量,但是可以有委托和事件。
  3. 接口中成员不许有访问修饰符,默认为public,手动添加会编译出错。 接口中成员只有定义,没有任何实现,像抽象类一样
  4. 实现接口的类,直接实现接口中的方法,不用写override。
  5. 当显示该接口的成员时,实例成员不能通过类实例访问(不提倡用类实例访问,这样就无法体现多态性),只能通过接口实例访问,显示实现默认是private。当隐示实现接口成员,两者实例都能访问,但是要将成员表示为public。

    比如:
   public class Person : IFace1, IFace2
{
public void Fly()
{
Console.WriteLine("实现了IFace1中的Fly方法。");
} //显示实现接口的访问修饰符默认是没有的,类中成员没有写访问修饰符这默认就是private
//显示实现接口是私有的所以必须通过接口名才能访问的到。
void IFace2.Fly()
{
Console.WriteLine("实现了IFace2中的Fly方法。");
}
} public interface IFace1
{
void Fly();
}
public interface IFace2
{
void Fly();
}
Person p = new Person();
p.Fly();//face1中的Fly()face2中显示实现,为private,通过new Person 无法获取到。 IFace1 f1 = new Person();
f1.Fly();//face1中的Fly() IFace2 f2 = new Person();
f2.Fly();//face2中的Fly()

virtual和override的应用

virtual是虚函数的关键词,override是重写的关键词。有virtual关键词,意味允许继承者可以用override重写。如果不用override,则不是重写。

例如:

 class Person
{
public virtual void Introduce()
{
Console.WriteLine("我是来自地球");
}
} class Chinese : Person
{
public override void Introduce()
{
Console.WriteLine("我的户口,身份证号码");
}
}
class American : Person
{
//此处没有加override,所以在后续代码中无法调用此方法。
public void Introduce()
{
Console.WriteLine("社会保险号:00000");
}
}

Person p1 = new Chinese();

p1.Introduce();

Person p2 = new American();

p2.Introduce();

显示的结果为:我的户口,身份证号码。我是来自地球

当一个抽象类实现接口的时候,如果不想把接口成员实现,可以把成员实现为abstract。

为什么不能指定接口中方法的修饰符?

接口中的方法用来定义对象之间通信的契约,指定接口中的方法为私有或保护没有意义。它们默认为公有方法。

抽象类

抽象类是包含抽象方法的类。那么什么又是抽象方法呢?抽象方法是没有方法内容的,只有一个方法名和参数列表的方法。并以;结尾。为了标注他的与众不同,在他的返回类型前加abstract。并在class前加abstract。

简言之,由abstract修饰的方法和类就是抽象的方法和类。

 //抽象状态类State,定义一个接口以封装与Context的一个特定状态相关的行为
abstract class State
{
public abstract void Handle(Context context);
} //ConcreteState类,具体状态,每一个子类实现一个与Context的一个状态相关的行为
class ConcreteStateA : State
{
public override void Handle(Context context)
{
//设置ConcreteStateA的下一个状态是ConcreteStateB
context.State = new ConcreteStateB();
}
} class ConcreteStateB : State
{
public override void Handle(Context context)
{
//设置ConcreteStateB的下一个状态是ConcreteStateA
context.State = new ConcreteStateA();
} }

抽象类不能实例化,必须通过继承由派生类实现其抽象方法,因此对抽象类不能使用new关键字,也不能被密封。如果派生类没有实现所有的抽象方法,则该派生类也必须声明为抽象类。另外,实现抽象方法由override方法来实现。

接口与抽象类的相同点:

1、不能实例化;

2、包含未实现的方法声明;

3、派生类必须实现未实现的方法,抽象类是抽象方法,接口则是所有成员(不仅是方法包括其他成员);

接口和抽象类的区别

1.类是对对象的抽象,可以把抽象类理解为把类当作对象,抽象成的类叫做抽象类.而接口只是一个行为的规范或规定

2.接口基本上不具备继承的任何具体特点,它仅仅承诺了能够调用的方法;

3.一个类一次可以实现若干个接口,但是只能扩展一个父类

4.接口可以用于支持回调,而继承并不具备这个特点.

5.抽象类不能被密封。

6.抽象类实现的具体方法默认为虚的,但实现接口的类中的接口方法却默认为非虚的,当然您也可以声明为虚的.

7.(接口)与非抽象类类似,抽象类也必须为在该类的基类列表中列出的接口的所有成员提供它自己的实现。但是,允许抽象类将接口方法映射到抽象方法上。

8.抽象类实现了oop中的一个原则,把可变的与不可变的分离。抽象类和接口就是定义为不可变的,而把可变的座位子类去实现。

9.好的接口定义应该是具有专一功能性的,而不是多功能的,否则造成接口污染。如果一个类只是实现了这个接口的中一个功能,而不得不去实现接口中的其他方法,就叫接口污染。

10.尽量避免使用继承来实现组建功能,而是使用黑箱复用,即对象组合。因为继承的层次增多,造成最直接的后果就是当你调用这个类群中某一类,就必须把他们全部加载到栈中!后果可想而知.(结合堆栈原理理解)。同时,有心的朋友可以留意到微软在构建一个类时,很多时候用到了对象组合的方法。比如asp.net中,Page类,有Server Request等属性,但其实他们都是某个类的对象。使用Page类的这个对象来调用另外的类的方法和属性,这个是非常基本的一个设计原则。

11.如果抽象类实现接口,则可以把接口中方法映射到抽象类中作为抽象方法而不必实现,而在抽象类的子类中实现接口中方法.

12. 接口定义方法,不能实现,而抽象类可以实现部分方法。

13.接口中基本数据类型为static 而抽类象不是的。

抽象类的功能要远超过接口,但是,定义抽象类的代价高。因为高级语言来说(从实际设计上来说也是)每个类只能继承一个类。在这个类中,你必须继承或编写出其所有子类的

所有共性。虽然接口在功能上会弱化许多,但是它只是针对一个动作的描述。而且你可以在一个类中同时实现多个接口。在设计阶段会降低难度的。

如何理解抽象类和接口

1.飞机会飞,鸟会飞,他们都继承了同一个接口“飞”;但是F22属于飞机抽象类,鸽子属于鸟抽象类。

2.就像铁门木门都是门(抽象类),你想要个门我给不了(不能实例化),但我可以给你个具体的铁门或木门(多态);而且只能是门,你不能说它是窗(单继承);一个门可以有锁(接口)也可以有门铃(多实现)。门(抽象类)定义了你是什么,接口(锁)规定了你能做什么(一个接口最好只能做一件事,你不能要求锁也能发出声音(接口污染))。

什么时候用接口实现多态?

答:当多个类型不能抽象出合理的父类时,但是又要对一些方法进行多态,此时可以考虑用接口。讲公共的方法抽象到一个接口中。

程序设计的原则(自己听课的结果)

  1. 接口》抽象类》父类》具体类(在定义方法参数、。返回值、声明变量的时候能使用抽象就不要使用具体参数。
  2. 能使用接口就不要使用抽象类,能使用抽象类就不要用类,能用父类就不要用子类。
  3. 避免使用”体积庞大的接口“”多功能接口“会造成接口污染。
  4. 单一职责、开放封闭、里氏替换、接口隔离、依赖接口