多态

本篇讲解实现多态的三种方法:虚方法、抽象方法和接口。

人类都能说话,但是不同国家的人可能使用的语言不一样,所以,不同国家的人说同样的话,会有不同的表现形式(同一事情,不同表现形态),如何用程序体现这种差异呢?

 1  class Program
 2     {
 3         static void Main(string[] args)
 4         {
 5             Person[] ps = new Person[5];
 6             ps[0] = new Chinese();
 7             ps[1] = new British();
 8             ps[2] = new Japanese();
 9 
10             for (int i = 0; i < ps.Length; i++)
11             {
12                 if (ps[i] is Chinese)
13                 {
14                     Chinese c=(Chinese)ps[i];
15                     c.Introduce();
16                 }
17 
18                 if (ps[i] is British)
19                 {
20                     British c = (British)ps[i];
21                     c.Introduce();
22                 }
23 
24                 if (ps[i] is Japanese)
25                 {
26                     Japanese c = (Japanese)ps[i];
27                     c.Introduce();
28                 }
29             }
30 
31             Console.ReadKey();
32         }
33     }
34 
35     public class Person
36     {
37         public string Name { get; set; }
38     }
39 
40     public class Chinese:Person
41     {
42         public void Introduce()
43         {
44             Console.WriteLine("我是中国人");
45         }
46     }
47 
48     public class British : Person
49     {
50         public void Introduce()
51         {
52             Console.WriteLine("我是英国人");
53         }
54     }
55 
56     public class Japanese : Person
57     {
58         public void Introduce()
59         {
60             Console.WriteLine("我是日本人");
61         }
62     }
View Code

上面的代码能体现这种差异,但是会留下其他问题。1.for循环中的if判断会随着数组中的元素增加而增多。2.数组增加一个元素就需要改动以前的代码(添加if判断),违背了程序的开闭原则(对扩展开放,对修改关闭)。如果用虚方法就能避免这个问题。

一、虚方法

下面是虚方法的代码:

 1 class Program
 2     {
 3         static void Main(string[] args)
 4         {
 5             Person[] ps = new Person[3];
 6             ps[0] = new Chinese();
 7             ps[1] = new British();
 8             ps[2] = new Japanese();
 9 
10             for (int i = 0; i < ps.Length; i++)
11             {
12                 //if (ps[i] is Chinese)
13                 //{
14                 //    Chinese c=(Chinese)ps[i];
15                 //    c.Introduce();
16                 //}
17 
18                 //if (ps[i] is British)
19                 //{
20                 //    British c = (British)ps[i];
21                 //    c.Introduce();
22                 //}
23 
24                 //if (ps[i] is Japanese)
25                 //{
26                 //    Japanese c = (Japanese)ps[i];
27                 //    c.Introduce();
28                 //}
29 
30                 ps[i].Introduce();//调用同一个方法,输出不同的结果。对同一事情,作出不同的反应。
31             }
32 
33             Console.ReadKey();
34         }
35     }
36 
37     public class Person
38     {
39         public string Name { get; set; }
40 
41         public virtual void Introduce()
42         {
43             Console.WriteLine("我是中国人");
44         }
45     }
46 
47     public class Chinese:Person
48     {
49         public override void Introduce()
50         {
51             Console.WriteLine("我是中国人");
52         }
53     }
54 
55     public class British : Person
56     {
57         public override void Introduce()
58         {
59             Console.WriteLine("我是英国人");
60         }
61     }
62 
63     public class Japanese : Person
64     {
65         public override void Introduce()
66         {
67             Console.WriteLine("我是日本人");
68         }
69     }
View Code

用虚方法能避免上面的两个问题。

注意:

1.虚方法的两个关键字:virtual和override。

2.虚方法可以重新,也可以不重写。如果子类有与父类虚方法重名方法,但是又想说明这个方法不是重写的方法,可以加new关键字。

3.用虚方法实现多态后,父类变量传入子类对象,父类变量调用的方法都是父类中已有的方法,只不过实现的方式不一样。如果子类没有重写虚方法(子类中没有显式的写这个方法),此时调用的方法也可以理解为是子类中的,(子类继承父类的),只不过没有显示。

 积累:

object 中有ToString(),因为所有的类都继承类object,所以所有的类都有ToString()方法。但是不同的类调用ToString后的结果不同,这取决于这个类中的ToString()方法是怎么实现的。如:

 1 class Program
 2     {
 3         static void Main(string[] args)
 4         {
 5             object obj = new object();
 6             Console.WriteLine(obj.ToString());
 7 
 8             string[] names = new string[] { "a","b","c"};
 9 
10             Console.WriteLine(names.ToString());
11 
12             string agrs = new string(new char[] { 'a', 'b', 'c' });
13             Console.WriteLine(agrs.ToString());
14 
15             int a = 12;
16             Console.WriteLine(a.ToString());
17 
18             Console.ReadKey();
19         }
20     }
View Code

输出的结果依次是:System.Object,System.String[],abc,12。反编译后发现,前面两种类型的ToString()方法中是返回this.GetType().ToString().后两者返回的结果最终都是this,即当前对象。

二、抽象方法

用抽象方法实现文章开头的问题的代码:

 1 class Program
 2     {
 3         static void Main(string[] args)
 4         {
 5             Person[] ps = new Person[2];
 6             ps[0] = new Chinese();
 7             ps[1] = new Japanese();
 8 
 9             for (int i = 0; i < ps.Length; i++)
10             {
11                 ps[i].Introduce();
12             }
13 
14             Console.ReadKey();
15         }
16     }
17 
18     public abstract class Person
19     {
20         public abstract void Introduce();
21     }
22 
23     public class Chinese : Person
24     {
25         public override void Introduce()
26         {
27             Console.WriteLine("我是中国人");
28         }
29     }
30 
31     public class Japanese : Person
32     {
33         public override void Introduce()
34         {
35             Console.WriteLine("我是日本人!");
36         }
37     }
View Code

用虚方法和用抽象方法实现多态的区别

1.虚方法必须有方法体,抽象方法没有。

2.子类可以实现虚方法,也可以不实现。但是抽象方法必须实现(除非子类也是抽象类 )。可见,用抽象方法实现多态,父类对子类控制得更严格。

 

虚方法和抽象方法实现多态的场景

1.如果子类的实现方式都不一样,那么父类就没必要存在方法体,考虑用抽象方法。

2.如果父类没必要实例化,考虑用抽象方法。

 

三、接口

1.接口是一种规范,是一种能力。

2.接口中只能包含方法(属性,事件,索引本质上都是方法)

3.能实现多态,代码如下:

 1 class Program
 2     {
 3         static void Main(string[] args)
 4         {
 5             IFlyable supperMan = new SupperMan();
 6             supperMan.Fly();
 7             IFlyable spiderMan = new SpiderMan();
 8             spiderMan.Fly();
 9             Console.ReadKey();
10         }
11     }
12 
13     public interface IFlyable
14     {
15         void Fly();
16     }
17 
18     public class SupperMan : IFlyable
19     {
20         public void Fly()
21         {
22             Console.WriteLine("超人会飞……");
23         }
24     }
25 
26     public class SpiderMan : IFlyable
27     {
28         public void Fly()
29         {
30             Console.WriteLine("蜘蛛侠也会飞……");
31         }
32     }
View Code

上面的代码可用抽象方法实现,为何还用接口实现?如果现在我再加个鸟类,也实现了飞的方法,但是鸟,蜘蛛侠,超人却无法抽象出一个父类,此时可以考虑用接口达到这个目的。

总结:

虚方法,抽象方法,接口都能实现多态,那各自的应用场景是什么呢?

1.虚方法中的方法必须有方法体,子类可以实现。

2.抽象方法不用实现,子类必须显式的实现。当子类的相同动作,实现的方式不同的时候,可以在父类中定义抽象方法(因为父类不用实现,事实上父类中的方法也不知道怎么实现)。当然也可以用接口。

3.当多个类都需要实现某个动作,但是这几个类却无法抽象出一个共同的父类的时候,可以用接口实现。类可以实现多个接口,但是只能继承一个父类,接口可以解决继承的单根性问题。

 

posted @ 2017-02-09 15:51  wesley1680  阅读(135)  评论(0编辑  收藏  举报