1、继承关系实现多态
2、抽象类和抽象方法以及通过抽象方法实现多态
3、接口及多继承性及通过接口实现多态
4、多态的应用原则
5、简单工厂设计模式
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("移动硬盘写数据中");
}
}
}