OOP Principles
2021-01-02
0. 前言
简要介绍面向对象编程的 4 个原则:
- Encapsulation
- Abstraction
- Inheritance
- Polymorphism
1. Encapsulation 封装
private vs public
有些东西是别人能看到的,有些是只有自己知道的。
private 的东西自己负责管理,public 的东西可以被别人使用和改变。
object 之间只能通过 public methods 来沟通。
比如:一个人的思想是 private 的,但 TA 说的话是 public 的,别人可以通过和这个人说话来交互,但是不能直接看到这个人脑子里在想什么。
In object-oriented terms, we say that the public members encapsulate the private members of the class.
2. Abstraction 抽象
object 需要把复杂的细节藏起来,只提供别人需要的,而不是全部。
抽象的目的就是让我们可以方便的让别人做一些事情,不需要关心这件事到底是怎么完成的。
比如:
- 顾客需要知道餐厅的营业时间和菜单,不需要知道餐厅的内部安排和人员分配;
- 你只需要按开机键就可以打开手机,不需要关注手机到底是怎么启动的;
- 老板嘱咐下属预订明晚的饭局,不需要知道下属具体是怎么预定的。
因为有了抽象这个概念,我们可以在不影响别人的情况下去修改具体的实现过程,只要最终能达到一样的结果就行了。
比如:
- 老板让小王去预订饭局,小王让小刘帮忙做这件事,老板最终获得的结果是一样的。
为什么要有封装和抽象呢?
因为当 object 数量越来越多之后,假如每个 object 要关心一大堆跟它无关的事情,就没法集中精力管好自己的事情。
别忘了,程序是人写的,也是需要人去读懂去维护的,假如一个人需要考虑的事情太多了,千条万缕反而会抓不住重点,随着项目规模的扩大,出错的概率也就越大。
程序员们发现让每个 object 各司其职能减少脱发,这也跟我们之前说的 SOLID principle 里面的单一责任有异曲同工之妙(OOP 的项目天生具有 Single Responsibility 的属性呀~)。
3. Inheritance 继承
人们又发现,当两个 object 非常相似(但不完全一样)的时候,假如能够有个继承的概念,就可以减少一大堆的工作量和重复代码。
于是就有了 parent - child 这一对概念,也被称为 base class - subtype class。
child 继承了 parent 的特性,也有自己独特的属性,继承是单向的(也就是 parent 不能继承 child)。
比如:
- 公立学校和私立学校都是学校,它们有一些共性又不完全一样,那我们就先创建一个学校作为 parent class,然后让公立学校和私立学校成为 child class。
继承的好处就在于我们可以重复使用 parent 的属性,建立不同 class 之间的一种父子关系。
可替换术语
- superclass - subclass
- parent - child
- base - subtype
- Is-a relationship (cat is an animal, child is a parent)
4. Polymorphism 多态
当 parent 和 child 对于同一个问题有不同的解决方案时,听谁的?
首先,child 有着 parent 所有的属性(还记得吗?SOLID 里面讲到的 Liskov Substitution Principle 里氏替换原则,就是说 child 可以替换 parent);
其次,在程序运行的过程中,一个 object 可能是被当成 parent 来用的,也可能是被当成 child 来用的,到底是哪个,运行的时候才知道;
比如我们有个 school list,里面有不同的学校类型,由于子类可以替换父类,所以可以用父类来代表 list 里面所有的学校:
School[] schools = new School[2];
schools[0] = new PublicSchool();
schools[1] = new PrivateSchool();
School, PublicSchool, PrivateSchool 都有一个 GetEnrollmentFee()
的方法,各自返回不同的结果,子类方法 override 父类方法。
在运行的时候,即使这两个 object 是 School(父类)类型,也会调用子类(PublicSchool、PrivateSchool)里面的方法,因为程序运行时它事实上就是一个子类。
反之,假如子类没有 override 父类方法,那么在运行时会继续使用父类方法。
// result: 100, 500
void Main()
{
School[] schools = new School[2];
schools[0] = new PublicSchool();
schools[1] = new PrivateSchool();
foreach(School s in schools){
s.GetEnrollmentFee();
}
}
class School
{
public virtual void GetEnrollmentFee(){
Console.WriteLine("100");
}
}
class PublicSchool: School{
}
class PrivateSchool : School
{
public override void GetEnrollmentFee()
{
Console.WriteLine("500");
}
}
简而言之,多态就是指程序在运行中可以判断 object 类型并且根据 runtime object type 来调用方法。
Note: 多态可以用来解决代码中复杂的 if else 逻辑。