1、继承关系实现多态:一种调用,多种实现。 1)多态:隐藏基类 —new 则隐藏,隐藏看类型(来决定调用父类还是子类的方法): 条件:父类子类写同名方法,子类方法名前加new(可以不加new) 结果:对象的类型是子类则调用子类方法;是父类则调用父类方法 2)多态:重写 —over重写,重写只管新(调用新重写的方法): 条件1: 继承、里氏转换原则,且父类和子类有同名的方法 在父类方法前加上virtual,在子类方法前加上override 结果: 实现用父类对像调用子类方法 3)隐藏基类应用:重写的子类调用自定义方法,不重写的继承父类方法,实现多态 父类提供ToString方法,子类继承下来,可以直接调用ToString方法。 不重写:如果子类,没有提供ToString方法,那么直接使用object提供的。 重写:如果用户提供了ToString方法,那么调用时,就可以调用自定义的方法。 (开放封闭原则:对扩展开放,对修改封闭。) 4)重写方法实例:父类根据指向的子类不同,调用不同子类的方法,实现多态。
View Code
class Program { static void Main(string[] args) { Father f = null; Console.WriteLine("你要使用什么元件?(1、手机;2、灯)"); switch (Console.ReadLine()) { case "1": f = new Phone("手机"); break; case "2": f = new Light("Usb灯"); break; } f.Usb(); } } class Father { string name; ---此处省略数行--- public virtual void Usb() { Console.WriteLine("父类方法!"); } } class Phone : Father { public Phone(string name) : base(name) { } public override void Usb() { Console.WriteLine("正在充电!"); } } class Light : Father { public Light(string name) : base(name) { } public override void Usb() { Console.WriteLine("亮灯!"); } }
2、抽象类(难点)带有abstract的类 抽象类是对一类事物或对象的抽象,统一了一类对象。 ->抽象类当中的成员 ->抽象成员:方法、属性(、索引、事件声明) ->非抽象成员,如Shape类中name ->抽象类的使用 ->抽像类就是为了实现多态的,在使用多态的地方几乎都可以使用抽象 ->抽象类是不能被实例化的,抽象类有构造方法(给非抽象成员赋初值) ->抽象成员的使用 (1)抽象方法的使用 父类:[]abstract 返回类型 方法名() {}子类:[]override 返回类型 方法名() {} (2)抽象属性的使用 快捷键Shift+Alt+F10 (3)抽象属性 -> 抽象与自动属性,本质不同 -> 自动属性,后台会有一个字段生成,体统会自动的添加对应的方法体 -> 抽象属性,因为没有方法体,所以get,set中什么都没有 -> 抽象与自动属性,结果不同 -> 自动属性,get,set必须共存 -> 抽象属性是可以有:只读、只写、可读可写之分的 3、抽象方法实现多态(简单的说与继承关系父类使用多态相似) 不知道怎么实现;不需要实现,[public] abstract 返回类型 方法名( ); 抽象方法必须在抽象类中,方法和类前面都有abstract 抽象方法是为了实现多态,子类必须重写父类中的抽象方法 public override 父类提供的方法名(){} 特例:如果子类也是抽象的,可以不重写父类分抽象方法 实例:形状类(抽象父类),圆形、长方形、正方形三个子类,实现父类调用子类方法求周长和面积
View Code
namespace AbstractClass { class Program { static void Main(string[] args) { while (true) { Shape[] s = { new Circle("小圆",10), new Rectangle("小长",27.5,30), new Square("小方",100) }; for (int i = 0; i < s.Length; i++) { s[i].Introduction(); Console.WriteLine("我的面积是:{0}",s[i].Area()); Console.WriteLine("我的周长是:{0}",s[i].Perimeter()); } Console.ReadKey(); } } } } abstract class Shape { //字段 属性 string name; public string Name { get { return name; } set { name = value; } } double pi = 3.14; public double Pi { get { return pi; } set { pi = value; } } //构造方法 public Shape(string name) { this.name = name; } //抽象父类方法 public abstract void Introduction(); public abstract double Area(); public abstract double Perimeter(); } class Circle : Shape { //字段 属性 double r; public double R { get { return r; } set { r = value; } } //构造方法 public Circle(string myname,double r1):base(myname) { r = r1; } //圆形子类方法 public override void Introduction() { Console.WriteLine("我是一个圆:我叫{0}",Name); } public override double Area() { double area = 0; area = Pi * r * r; return area; } public override double Perimeter() { double perimeter; perimeter = 2 * Pi * r; return perimeter; } } class Rectangle : Shape { double length; public double Length { get { return length; } set { length = value; } } double width; public double Width { get { return width; } set { width = value; } } public Rectangle(string myname, double len,double wid) : base(myname) { length = len; width = wid; } public override void Introduction() { Console.WriteLine("我是矩形:{0}",Name); } public override double Area() { double area = 0; area = 2 * (length + width); return area; } public override double Perimeter() { double area = 0; area = length * width; return area; } } class Square : Shape { double a; public double A { get { return a; } set { a = value; } } public Square(string myname, double a1) : base(myname) { a = a1; } public override void Introduction() { Console.WriteLine("我是正方形:{0}",Name); } public override double Area() { double area = 0; area = 4 * a; return area; } public override double Perimeter() { double area = 0; area = a * a; return area; } }
4.1、接口(与使用抽象类类似) 接口是对能力和方法的抽象。 [public] interface 接口名 { // 接口成员 } -> 接口成员 -> 仅仅抽象能力,所以只有方法、属性、索引、事件声明 -> 接口中的成员就相当于抽象类中的抽象成员 -> 接口的定义和实现接口 -> 定义接口方法不用写访问修饰符,默认public -> 子类继承自接口,实现接口中的方法时,写一个正常方法 (没有override) 4.2、接口的多继承性(有同名方法的处理) (1)显式实现接口: 通过显式实现接口的方式为特定的接口重写特定的方法,调用方法时根据变量所属的接口类型来选择相应的方法。 (2)调用接口:返回类型 接口名.方法名()显式实现的方法只能由接口调用 接口类的对象优先调用显式实现接口的方法,缺少的情况,再调用非显式实现的方法。 非接口类对象,只能调用非显式实现的方法,不能调用显式实现接口的方法。 示例: class Duck4 : Duck,IJiaoable1, IJiaoable2 { public void Jiao() { Console.WriteLine("普通实现接口"); } void IJiaoable1.Jiao() { Console.WriteLine("显式实现接口IDuck1"); } void IJiaoable2.Jiao() { Console.WriteLine("显式实现接口IDuck2"); } } 显式实现接口,Shift+Alt+F10生成,不加访问修饰符的(跟接口中一样) 5、接口实现多态:鸭子的实例-联合使用继承和接口实现多态 不同鸭子游泳的方法不一样,所有鸭子都会游泳(继承) 不同鸭子叫的方法不一样,有的还不会叫(接口)
View Code
class Program { static void Main(string[] args) { Duck[] d = { new RealDuck(), new RubberDuck(),new WoodDuck()}; for (int i = 0; i < d.Length; i++) { d[i].Swim(); IJiaoable dk = d[i] as IJiaoable; if (dk != null) { dk.Jiao(); } } Console.ReadKey(); } } abstract class Duck { public abstract void Swim(); } interface IJiaoable { void Jiao(); } class RealDuck : Duck, IJiaoable { public override void Swim() { Console.WriteLine("我是真的鸭子,我会游泳!我游啊游~~~"); } public void Jiao() { Console.WriteLine("我是真的鸭子,嘎嘎嘎!"); } } class RubberDuck : Duck, IJiaoable { public override void Swim() { Console.WriteLine("我是橡皮鸭子,我会游泳!我游啊游~~~"); } public void Jiao() { Console.WriteLine("我是橡皮鸭子,唧唧~~唧唧~~"); } } class WoodDuck : Duck //没有叫的方法,于是不实现IJiaoable接口 { public override void Swim() { Console.WriteLine("我是木头鸭子,我会游泳!我游啊游~~~"); } }
6.多接口中有同名方法的调用 根据对象的接口类型,优先调用显式实现的该接口方法。 没有针对该接口的显式实现方法可调用时,调用非显式实现的方法。 显式实现接口,Shift+Alt+F10生成,不加访问修饰符的(跟接口中一样)
演示:普通实现接口和显示实现接口的调用
执行结果: Duck1,普通实现接口 Duck1,普通实现接口 Duck2,显式实现接口IJiaoableA Duck2,普通实现接口 Duck3,普通实现接口 Duck3,显式实现接口IJiaoableB Duck4,显式实现接口IJiaoableA Duck4,显式实现接口IJiaoableB 代码清单:
View Code
namespace 显式实现接口演示 { class Program { static void Main(string[] args) { Duck[] dk = { new Duck1(), new Duck2(),new Duck3(),new Duck4() }; for (int i = 0; i < 4; i++) { IJiaoableA dka = dk[i] as IJiaoableA; if (dka != null) dka.Jiao(); IJiaoableB dkb = dk[i] as IJiaoableB; if (dkb != null) dkb.Jiao(); Console.WriteLine(); } Console.ReadKey(); } } public abstract class Duck { } interface IJiaoableA { void Jiao(); } interface IJiaoableB { void Jiao(); } //普通实现接口:不针对两个接口分别写方法 class Duck1 : Duck, IJiaoableA, IJiaoableB { public void Jiao() { Console.WriteLine("Duck1,普通实现接口"); } } //普通实现接口+显式实现接口“IDuck1” class Duck2 : Duck,IJiaoableA, IJiaoableB { public void Jiao() { Console.WriteLine("Duck2,普通实现接口"); } void IJiaoableA.Jiao() { Console.WriteLine("Duck2,显式实现接口IJiaoableA"); } } //普通实现接口+显式实现接口“IDuck2” class Duck3 : Duck,IJiaoableA, IJiaoableB { public void Jiao() { Console.WriteLine("Duck3,普通实现接口"); } void IJiaoableB.Jiao() { Console.WriteLine("Duck3,显式实现接口IJiaoableB"); } } //普通实现接口+显式实现接口“IDuck1”+显式实现接口“IDuck2” class Duck4 : Duck,IJiaoableA, IJiaoableB { public void Jiao() { Console.WriteLine("Duck4,普通实现接口"); } void IJiaoableA.Jiao() { Console.WriteLine("Duck4,显式实现接口IJiaoableA"); } void IJiaoableB.Jiao() { Console.WriteLine("Duck4,显式实现接口IJiaoableB"); } } }
7、多态的应用原则
多态实现方式:接口实现多态(对外)、抽象实现多态、父类实现多态(对内) 开发过程: 定义接口—定义抽象—父类—子类,最终使用的是子类,给用户的是接口。 开发以抽象为主,能够抽象,尽量不要使用具体。 接口的使用原则:单一功能,组合使用。 抽象类是对一类事物的抽象,接口是对能力和方法的抽象。 8、简单工厂设计模式(使项目模块化,可以将不同模块分给不同的项目小组去完成和维护) 思路:在Main方法中使用父类变量接收工厂方法的子类对象,实现了“统一调用,不同实现”的多态性。 步骤:写一个父类(抽象、具体、接口),定义统一的执行标准 写若干个子类,分别重写父类方法或实现接口的方法 写一个Factory类,根据需求new出子类,赋给父类变量返回 Mian方法中完成需求输入,调用Factory类方法,得到对象调用特定子类的方法。
演示:多态实现不同移动设备各自的读写操作 运行结果: 请选择您的设备类型: 输入编号或简码: 1.U盘(u/U), 2.Mp3(m/M), 3.移动硬盘(h/H) 1 U盘读数据中 U盘写数据中 请选择您的设备类型: 输入编号或简码: 1.U盘(u/U), 2.Mp3(m/M), 3.移动硬盘(h/H) 2 Mp3读数据中 Mp3写数据中 Mp3播放音乐中 请选择您的设备类型: 输入编号或简码: 1.U盘(u/U), 2.Mp3(m/M), 3.移动硬盘(h/H) 3 移动硬盘写数据中 移动硬盘读数据中 代码清单:
View Code
namespace IMoveMemableDemo { class Program { static void Main(string[] args) { while (true) { //请用户插入移动设备 Console.WriteLine("请选择您的设备类型:\n输入编号或简码: 1.U盘(u/U), 2.Mp3(m/M), 3.移动硬盘(h/H)"); //根据用户输入调用“工厂模式”方法返回对象 IMoveMemable device = Factory.GetDevice(Console.ReadLine()); //使用设备 应用多态 if (device != null) { device.Read(); device.Write(); Mp3 mp3 = device as Mp3; if (mp3!=null) mp3.PlayMusic(); } else { Console.WriteLine("您输入的设备类型不存在!"); } Console.WriteLine(); Console.WriteLine(); } } } public class Factory { public static IMoveMemable GetDevice(string name) { IMoveMemable device = null; switch (name) { case "1": case "u": case "U": device = new UDisk(); break; case "2": case "m": case "M": device = new Mp3(); break; case "3": case "h": case "H": device = new MHardDisk(); break; default: break; } return device; } } public interface IMoveMemable { void Write(); void Read(); } public class UDisk : IMoveMemable { public void Write() { Console.WriteLine("U盘写数据中"); } public void Read() { Console.WriteLine("U盘读数据中"); } } public class Mp3 : IMoveMemable { public void Write() { Console.WriteLine("Mp3写数据中"); } public void Read() { Console.WriteLine("Mp3读数据中"); } public void PlayMusic() { Console.WriteLine("Mp3播放音乐中"); } } public class MHardDisk : IMoveMemable { public void Write() { Console.WriteLine("移动硬盘读数据中"); } public void Read() { Console.WriteLine("移动硬盘写数据中"); } } }