面向对象-学习记录1
目标
寒假看了相关视频教程学了面向对象编程,时隔已久,现在回来复习并整理先前笔记。
是什么
面向对象是一种思想。从“对象”的角度出发思考问题。
面向对象有三个基本特征:
1.封装
2.继承
3.多态 把面向对象的思想发挥到了最高点
封装
用术语说:封装,即指隐藏对象的属性和实现细节,仅对外提供公共访问方式。
举个例子,假如我们做了个PVZ里的向日葵。那么,以后要产出阳光时,我们只需要知道:种向日葵,种就完事了。而无需关心向日葵内部是如何计算阳光的产出时间等细节,那是面向过程要考虑的事,是已经被封装好了的,我们直接用就好了。
好处
简化了问题。
继承
用术语说:继承,即子类继承父类的特征和行为,使得子类对象具有父类的属性和方法。
举个例子,PVZ里的西瓜投手和冰瓜投手。西瓜投手作为父类,冰瓜投手作为它的子类。前者有的,后者都有,这就是继承。
好处
减少代码冗余。
两个特点
- 单根性:一个子类只对应一个父类。
- 传递性:子类可调用父类及其父类中的成员。
里氏转换(视频教程里说里氏转换用得很多,一定要记得)
- 当方法中需要一个父类作为参数,可拿其子类代替之。(父类变量里装子类对象)
- 当父类里装的是子类对象时,可以将父类强制转换为该子类。
转换时可使用的关键字
-
is 返回布尔值
//代码片段 Watermelon w = new IceWatermelon(); if(w is IceWatermelon) //变量名 is 类的类型 { IceWatermelon iw = (IceWatermelon) w;//里氏转换 }
-
as 若转换成功,返回转换后的对象;若失败,则返回null。
//代码片段 Watermelon w = new IceWatermelon(); IceWatermelon iw = w as IceWatermelon;//里氏转换
多态
用术语说:多态,即让一个对象表现出来多种类型。亦可理解为一个父类拥有多个不同的子类。
举个例子,PVZ里的豌豆们。如果把豌豆射手作为父类,那么可以把寒冰射手、双发射手、机枪射手作为其子类。这三个子类虽然都继承于同一个父类,但互不相同,各有特点,这就是多态。
好处
把各个子类中的公共部分抽取出来,最大限度的取消各子类之间的差异性,减少代码冗余。
三种实现手段
- 虚方法
- 抽象类
- 接口
虚方法
步骤1. 将父类的方法标记为虚方法:在父类方法的返回值前加上关键字virtual,那么该函数可以被子类重写。
步骤2. 在子类的同名方法的返回值前加上关键字override,重写该方法。
class Peashooter
{
public virtual void Attack()
{
Console.WriteLine("发射一颗豌豆");
}
}
class IcePeashooter : PeaShooter
{
public override void Attack()
{
Console.WriteLine("发射一颗冰豌豆");
}
}
class Repeater : PeaShooter
{
public override void Attack()
{
Console.WriteLine("发射两颗豌豆");
}
}
class GatlingPea : PeaShooter
{
public override void Attack()
{
Console.WriteLine("发射四颗豌豆");
}
}
在虚方法的前提下,父类变量中装着谁的对象,就调用该对象所对应的同名函数。
抽象类
当父类中的方法不知道如何去实现时,可以考虑将父类写成抽象类,将方法写成抽象方法。
步骤1. 使用关键字abstract标记一个类为抽象类,标记一个方法为抽象方法。
步骤2. 在子类的同名方法的返回值前加上关键字override,重写该抽象方法(必须重写父类的所有抽象方法,除非该子类也是抽象类)。
abstract class Plant //定义抽象类Plant
{
public abstract void Attack();//注意抽象父类的抽象方法无方法体
}
class Peashooter : Plant
{
public override void Attack()
{
Console.WriteLine("发射一颗豌豆");
}
}
class IcePeashooter : Plant
{
public override void Attack()
{
Console.WriteLine("发射一颗冰豌豆");
}
}
class Repeater : Plant
{
public override void Attack()
{
Console.WriteLine("发射两颗豌豆");
}
}
class GatlingPea : Plant
{
public override void Attack()
{
Console.WriteLine("发射四颗豌豆");
}
}
抽象方法不允许有方法体(花括号),有方法体没语句那叫空实现。
抽象类和接口都不允许实例化。
接口
想要多继承时,由于继承的单根性,只能使该子类继承一个接口。
步骤1. 定义一个接口。
步骤2. 在子类中实现接口里的所有成员。
接口中包含一组方法。使用接口可以强制规定其实现类必须要实现这些方法,而每个实现类的实现方式却又可以不同,这很多态。
一个接口可以有多个实现,一个实现类可以实现多个接口。
语法
public interface 接口名(一般为I...able)
{
成员;
}
示例代码片段
还记得PVZ中的特殊关“植物僵尸”吗?
public interface IPlantable //定义一个Plant接口,使僵尸也能拥有植物的能力
{
void Attack();
}
class PeaZombie : IPlantable
{
public void Attack()
{
Console.WriteLine("这个僵尸能发射豌豆");
}
}
class SquashZombie : IPlantable
{
public void Attack()
{
Console.WriteLine("这个僵尸能压扁遇到的第一株植物");
}
}
1.接口中的成员不允许添加访问修饰符,默认就是public。
2.接口中的成员不允许有方法体。
3.接口中不能包含字段(接口不存数据)。
4.继承接口的子类必须实现该接口的所有成员。
5.若一个类既继承了接口,又继承了类,那么在语法上,类必须写在接口之前。
参考资料
C#开发课程,一整套课程中的面向对象部分