面向对象基础
面向对象中最常提到的就是对象,类,实例这些,
既然是面向对象的话,那先从对象谈起,
对象
首先,一切事物皆为对象,对象是一个实体,其可以包含自己的特性和特定的行为。
类
就是将一些对象所具有的相同属性和相同的行为进行提取出来,也就是抽象,
提取出来后便会组成一个集合,那么这个集合就是类,
所以类,也可以理解为是对类似的对象分类的意思。
实例
就是一个真实的对象,由于前面使用类来对对象进行了分类,提取了他们相似的属性和行为,
所以,其满足于这个类,也就是可以通过这个类来生成对应的实例,这就是所谓的实例化,
比如,一个人可以用一个类来描述,这个类应该有头发颜色,肤色,身高等等这样的属性,
然后还会有如走路,吃饭这样的行为,那么,便可以通过 new 这个人类来生成一个实例,
这就是实例化一个人类的实例。
构造函数
构造函数是用来对类实现初始化的,其没有返回值,在通过 new 一个实例的时候自动调用构造函数
需要提及的是,任何一个类都有构造函数,如果没有自定义构造函数的话,
系统会调用默认的构造函数来实现实例化对象,当然,如果自定义了构造函数的话,
那么系统默认的构造函数就失效了。
析构函数
一个类中只能有一个析构函数,且析构函数无法被继承和重载,
同时,无法使用程序调用析构函数,因为析构函数是自动被调用的,也就是程序员是无法控制何时调用析构函数的,
因为这是由垃圾回收器决定的,垃圾回收器检查是否存在应用程序不再使用的对象,
如果垃圾回收器认为某个对象符合析构,则调用析构函数,并且回收内存,
当程序退出时也会调用析构函数来回收内存。
属性
属性是一个方法或一对方法,但是在访问它的代码来看,它却是一个字段,而不是一个方法,
比如,在调用方法时,一般都是 . FunctionName(),而在访问字段时确是 . FieldName,
属性有两个方法,一个是用来设置值的 set(),一个是用来获取值的 get(),
可以通过这两个方法来实现对一个字段的访问控制,
比如只读控制(即只有 get 方法),
只写控制(即只有 set 方法)或者是可读可写(既有 set 方法,又有 get 方法)。
封装
每一个对象都包含了它能进行操作所需要的所有的信息,
所以,一个对象不必依赖其他对象来完成自己的操作,
这里的意思就是一个对象是可以独立存在的,
比如,一只狗,它可以将自己的名字,重量等信息封装起来,
这样这只狗便是一个完整的对象,是可以独立存在的,而不必依赖其他的动物。
封装的优点体现在:良好的封装是可以减少耦合的,类内部的实现是独立的,类具有清晰地对外接口。
继承
继承就是一种“是一个”的关系,也就是说,一个对象是另外一个对象的一部分,
如果单就功能来说的话,继承也可以理解为是功能上的扩展,比如原来的类的功能只是走路,
那么我可以通过继承原来的类,然后再在这个子类中添加一个跑步的类,这样就实现了功能的扩展,
也就是子类可以完成包括父类所有的功能在内的更多功能。
子类既然继承了父类,那么子类便继承了父类中的方法,字段,属性,事件,索引器等,
但是其中有一个是例外的,就是构造函数是不能被继承的,其只能被子类调用,而不能继承。
继承的优点体现在:修改和复用方便,代码得到共享,同时对扩展也是比较方便的,
但是继承滥用会出现一系列的问题:这是因为继承破坏了封装性,
从上面的继承关系来看,父类的非私有成员在子类中是可以完全访问的,
这样便增大了两个类之间的耦合度(继承是一种类与类之间的强耦合关系)。
然后,继承还有一个最大的缺点,那就是只要是父类改变了,
那么子类不得不变(因为其完全继承了父类)。
多态
多态表示的是不同的对象可以执行相同的动作,但要通过他们自己的实现代码来执行。
换句话说就是子类可以以父类的身份出现,但是在动态运行时,其执行的却是自己的代码,
但是需要注意的是,当子类以父类的身份出现时,子类中特有的属性和方法是便可以使用的。
为了使子类的实例完全接替来自父类的类成员,父类必须将该成员声明为虚拟的,
这个可以通过关键字 Virtual 来实现,然后,子类可以通过使用 override 关键字来重写父类中定义的方法,
也就是以自己的方式来实现父类中定义的方法。
多态的原理是当方法被调用时,无论对象是否被转换为其父类,
都只有位于对象继承链最末端的方法实现会被调用,
也就是说,虚方法是按照其运行时类型而非编译时类型进行动态绑定调用的。
抽象类
C# 中是可以使用抽象类和抽象方法的,抽象类有如下的特定:
其不能被实例化,
抽象类中定义的抽象方法必须在其子类重写,
只要是类中包含了一个及以上的抽象方法,那么这个类就是抽象类,必须用 abstract 描述类
接口
接口呢,是一个功能集合,一旦类实现了接口,类就可以支持接口所指定的所有属性和成员,
在声明接口时,是不允许提供接口中任何成员的执行方式的,所以接口是不能实例化的,并且不能有修饰符。
如果一个类实现了一个接口,那么这个类就必须要实现接口中的所有的方法和属性。
下面呢就是通过一个整体的 Demo 来实现上面的关于面向对象的基础部分的演练:
上面的例子中呢,有 Duck(鸭子这个抽象类),然后其下面有三个子类,
分别是天鹅(Swan),笨鸭(FoolDuck),玩具鸭(ToyDuck),
所有的鸭子都是会游泳的,所以直接把 Swim()方法写在了父类 Duck 中,
这样所有继承自 Duck 类的子类均会游泳了,因为都会有 Swim()这个方法。
然后,还定义了两个接口,一个是 Fly(也就是能不能飞行),还有一个就是 Quack(即能不能发出发出叫声),
然后定义了两个类来实现接口 Fly ,两个类的行为分别是能够飞和不能够飞,
然后就是定义了三个类来实现接口 Quack ,这三个类分别代表发出 GuaGua 声音,和发出 ZhiZhi 声音,
还有一个就是不会发出声音了。
下面就开始来写类了
首先,完成后的项目架构为
下面就来一个一个的看代码了
先是 Fly 接口
然后是实现了这个接口的两个类 CanFly 和 FlyNoWay
接口 Quack 即叫声部分的代码
实现了 Quack 接口的三个类
然后就是来看核心的 Duck 类了
最后就是继承自 Duck 类的三个子类了
再来看一下客户端的代码吧
上面就是整个 Demo 的所有代码了,
下面在给出效果吧