谈面向对象,要从面向过程谈起。
以C语言为例,在C语言中描述一个事物时,需要定义一个结构体,结构体包含了事物的各个属性,以小猫为例
struct cat {
char *id;
int age;
char *name;
}
在结构体中我们只能定义小猫的属性,不能定义小猫的行为。如果我们希望小猫执行一个动作,那么只能定义一个函数,将小猫作为参数传进去,在函数内改变小猫的一些属性。比如经过一年小猫的年龄增大,对应的age属性应该改变。
int age_increase(cat c) {
// 相关操作
}
因为cat中的属性,定义出来就是用来访问的,所以就没有权限修饰符这一说。我们只要获取到cat,就可以在任何地方自由的修改cat中的属性。这是非常危险的。
关于cat发生的任何行为,我们都需要定义一个函数来修改cat。
在面向对象编程中,引入了类的概念。类中不仅可以包含描述事物的数据结构,还可以包含事物可以执行的动作行为。以Java为例,定义一个Cat
class Cat {
private int age;
private String name;
private String id;
public int ageIncrease(int year) {
age = age + year;
return age;
}
}
类中既然可以定义小猫的行为动作,那么小猫的改变就可以由他自己来完成,所以他的属性就没有让其他事物访问的必要,因此可以用权限修饰符来规范小猫属性的访问权限。
这样小猫属性的改变,一定是由自己的动作引起,改变小猫属性的逻辑,一定在类中被定义。如果出现bug,我们可以确定,小猫状态的改变一定是类中的代码引起。而不是向面向过程中那样,可能在任何一个地方改变小猫的属性。
面向对象的第一个特性:封装
将对象的属性和行为封装在一个类中,成为一个整体。属性对外屏蔽,对外暴露可以发生的行为
在面向过程中,如果我们定义多个事物有公共属性,可以把这部分属性单独封装为一个结构体。比如小猫和小狗都是动物
struct animal {
int age;
char *name;
char *id;
}
struct cat {
struct animal a;
// 小猫特有的属性
}
struct dog {
struct animal a;
// 小狗特有的属性
}
在面向对象中我们可以使用继承来实现,将事物都有的属性和行为封装为一个类,我们称之为父类(Animal)。我们在实现子类时继承父类即可获取父类的属性和行为,并且可以利用重写来重新定义某一行为的具体实现。
class Animal {
private int age;
private String name;
private String id;
public void pay() {
// 支付方式的详细定义
}
}
class Cat extends Animal {
// 小猫特有的属性
public void pay() {
// 小猫的支付实现为,支付一些鱼
}
}
class Dog extends Animal {
// 小狗特有的属性
public void pay() {
// 小狗的支付实现为,支付一些骨头
}
}
面向对象的第二特性:继承
现在我要定义一个澡堂,小动物们可以来澡堂洗澡,洗完澡之后要支付。可以定义一个澡堂类,澡堂类中有一个方法,可以传入一个小动物作为参数。可是小动物们都可以来澡堂洗澡,我该将澡堂的参数类型定义为什么呢?定义为Animal类型,因为Cat和Dog都是Animal
class XiShuaShua {
public void cleanSelf(Animal animal) {
// 小动物在澡堂洗澡
// 洗完澡后支付
animal.pay();
}
}
这就是多态,面向对象的第三特性:多态,在方法重写之后,对于animal.pay(),如果这里的animal是Dog,那么将支付骨头,如果这里的animal是Cat,那么将支付小鱼。这就是动态绑定,运行时多态,对象引用的类型只有在运行期间才能确定。