面向对象-学习记录1

目标

寒假看了相关视频教程学了面向对象编程,时隔已久,现在回来复习并整理先前笔记

是什么

面向对象是一种思想。从“对象”的角度出发思考问题。

面向对象有三个基本特征:
1.封装
2.继承
3.多态 把面向对象的思想发挥到了最高点


封装

用术语说:封装,即指隐藏对象的属性和实现细节,仅对外提供公共访问方式。

举个例子,假如我们做了个PVZ里的向日葵。那么,以后要产出阳光时,我们只需要知道:种向日葵,种就完事了。而无需关心向日葵内部是如何计算阳光的产出时间等细节,那是面向过程要考虑的事,是已经被封装好了的,我们直接用就好了。

好处
简化了问题。


继承

用术语说:继承,即子类继承父类的特征和行为,使得子类对象具有父类的属性和方法。

举个例子,PVZ里的西瓜投手和冰瓜投手。西瓜投手作为父类,冰瓜投手作为它的子类。前者有的,后者都有,这就是继承。

好处
减少代码冗余。

两个特点

  1. 单根性:一个子类只对应一个父类。
  2. 传递性:子类可调用父类及其父类中的成员。

里氏转换(视频教程里说里氏转换用得很多,一定要记得)

  1. 当方法中需要一个父类作为参数,可拿其子类代替之。(父类变量里装子类对象)
  2. 当父类里装的是子类对象时,可以将父类强制转换为该子类。

转换时可使用的关键字

  1. is 返回布尔值

     //代码片段
     
     Watermelon w = new IceWatermelon();
     
     if(w is IceWatermelon) //变量名 is 类的类型
     {
     	IceWatermelon iw = (IceWatermelon) w;//里氏转换
     }
    
  2. as 若转换成功,返回转换后的对象;若失败,则返回null。

     //代码片段
     Watermelon w = new IceWatermelon();
     
     IceWatermelon iw  = w as IceWatermelon;//里氏转换
    

多态

用术语说:多态,即让一个对象表现出来多种类型。亦可理解为一个父类拥有多个不同的子类。

举个例子,PVZ里的豌豆们。如果把豌豆射手作为父类,那么可以把寒冰射手、双发射手、机枪射手作为其子类。这三个子类虽然都继承于同一个父类,但互不相同,各有特点,这就是多态。

好处
把各个子类中的公共部分抽取出来,最大限度的取消各子类之间的差异性,减少代码冗余。

三种实现手段

  1. 虚方法
  2. 抽象类
  3. 接口

虚方法

步骤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#开发课程,一整套课程中的面向对象部分

posted @ 2021-04-26 16:45  AshScops  阅读(89)  评论(0编辑  收藏  举报