最近刚开始学习设计模式,在学习初期,把面向对象这个概念弄明白是很有必要的。
之前接触过C语言的基础,后来又学了一点VB,不过这都不是面向对象的语言,当然在编程中也就无法体会到面向对象的思想。
最近接触了软件工程、UML之后才渐渐了解了面向对象的概念,继而又简单学习了一下C++、C#,下面以C#为工具来总结一下目前所认识的面向对象。
何为对象?
进入正题之前,我们先来探讨一下什么是“对象”,不要误会,此“对象”非彼“对象”→_→。
举个例子,一只小狗,它有眼睛、嘴巴、鼻子、颜色等静态特征(属性),也有吃东西、睡觉等动态特征(方法);又比如一个手机,它既有型号、大小等静态特征(属性),也有打电话、发短息等动态特征(方法)。所以,对对象简单的定义就是“对象是一个包含属性和方法的整体”。
面向对象编程(OOP)
早期的计算机编程是基于面向过程的方法,例如实现一个求圆的面积的功能:S=3.14*r*r,通过设计一个算法就可以解决问题。随着需求的不断提高,需要被解决的问题也变得越来越复杂,例如前段时间比较火的“捕鱼”游戏,在游戏中,有成千上万条鱼、无数子弹,还有渔网、海底装饰物等等,但在制作游戏的过程中,我们的编程人员不能根据每条鱼的外形,游动方式而写一段相应的代码吧,那还不累死……所以用面向过程的方法来解决就有些困难了,这时就要用到面向对象。
一切事物皆对象,我们可以将现实世界中的任何事物看成是对象,比如在“捕鱼”游戏的实现中,每条鱼就是一个对象,每张网是一个对象……但是为了避免枯燥乏味,不能只要一条鱼,一张网吧,所以,就要把所有的鱼的共同点找出来,抽象出一个“鱼类”,把所有网的共同点找出来,抽象出一个“网类”……然后用的时候就可以让个鱼类实例化出无数条鱼。所以说,面向对象解决了传统的面向过程的编程方法所无法解决的代码复用的问题。
面向对象的特征
面向对象有三大特征:封装、继承和多态。
封装
封装就是把客观的事物抽象成类,并且类把自己不想对外开放的成员“藏起来”,仅仅提供一些相应的接口供外界访问,实现了信息隐藏,提高了安全性。如一个钟表类,有时、分、秒等属性,有调整时间等方法,实现封装的代码为:
class Clock { private int hour, minute, second; public int Hour { get { return Hour; } set { Hour = value; } } public int Minute { get { return Minute; } set { Minute = value; } } public int Second { get { return Second; } set { Second = value; } } }
在代码中,hour、minute、second就是Clock类“藏起来”的属性,Hour、Minute和Second就相当于是外界访问Clock这些私有属性的接口。
继承
假如在整个捕鱼游戏中,有成千上万条鱼,虽然有许多种类的鱼,但这些鱼会有许多共同点,比如每条鱼在屏幕上都会有一个位置(x坐标和y坐标),都会向前游动等等,这时候就可以根据所有鱼的共同特征,抽象出来一个“鱼”类,这个“鱼”类中包含了所有鱼的共同点,因此在实例化每种鱼的时候都使得公用代码得到了共享,避免了重复。
class Fish { protected double x; protected double y; public Fish() { x = 0; y = 0; } public double X { get { return x; } set { x = value; } } public double Y { get { return y; } set { y = value; } } public void Swim(double distance_x, double distance_y) { x += distance_x; y += distance_y; } } class Turtle : Fish { public Turtle() : base() { } public void Turn() { //为了区别于其他的鱼,就给乌龟加一个转头并按原路返回的方法 //……相关代码…… //…………………… //…………………… //……相关代码…… } } class Mermaid : Fish { public Mermaid() : base() { } public void SwingArms() { //为了区别于其他的鱼,就给美人鱼加一个摇摆双臂的方法 //……相关代码…… //…………………… //…………………… //……相关代码…… } }
这时,Fish类就是父类(基类),Turtle类和Mermaid类就是子类(派生类)。
多态
多态就是用不同的对象调用调用相同的方法,执行不同的操作。还是用捕鱼游戏来举例子,假定美人鱼只能一直向前游,而乌龟可以向任意方向(游动的时候x坐标和y坐标都可以发生改变),则每种鱼就不能只是单单继承Fish的Swim方法了,应该让特定的鱼种继承了Swim方法之后能够有不同游法(虽然同样是游泳,但各有各游的方式,就如同小猫叫的时候是“喵”,小狗叫的时候是“汪”)。
实现方法便是在父类中
class Fish { protected double x; protected double y; public Fish() { x = 0; y = 0; } public double X { get { return x; } set { x = value; } } public double Y { get { return y; } set { y = value; } } public virtual void Swim(double distance_x, double distance_y) { } } class Turtle : Fish { public Turtle() : base() { } public void Turn() { //为了区别于其他的鱼,就给乌龟加一个转头并按原路返回的方法 //……相关代码…… //…………………… //…………………… //……相关代码…… } public override void Swim(double distance_x, double distance_y) { x += distance_x; y += distance_y; } } class Mermaid : Fish { public Mermaid() : base() { } public void SwingArms() { //为了区别于其他的鱼,就给美人鱼加一个摇摆双臂的方法 //……相关代码…… //…………………… //…………………… //……相关代码…… } public override void Swim(double distance_x, double distance_y) { //美人鱼游的时候只是x坐标发生改变 x += distance_x; } }
代码中,在Fish类中的Swim方法要变为虚方法(其函数体内可以为空),子类继承这个虚方法后进行重写(即根据自己的特点进行扩充或改变)。如果父类中的虚方法有形参,则子类中重写的时候,函数的形参列表要与父类中虚方法的形参列表一致。
如有不足与纰漏,恳请您留下宝贵意见与建议,感激不尽!