面向对象编程的英文缩写是 OOP,全称是 Object Oriented Programming。对应地,面向对象编程语言的英文缩写是 OOPL,全称是 Object Oriented Programming Language。

面向对象分析(OOA)和面向对象设计(OOD)。面向对象分析英文缩写是 OOA,全称是 Object Oriented Analysis;面向对象设计的英文缩写是 OOD,全称是 Object Oriented Design。OOA、OOD、OOP 三个连在一起就是面向对象分析、设计、编程(实现),正好是面向对象软件开发要经历的三个阶段。

面向对象编程中有两个非常重要、非常基础的概念,那就是类(class)和对象(object)。

  • 面向对象编程是一种编程范式或编程风格。它以类或对象作为组织代码的基本单元,并将封装、抽象、继承、多态四个特性,作为代码设计和实现的基石 。
  • 面向对象编程语言是支持类或对象的语法机制,并有现成的语法机制,能方便地实现面向对象编程四大特性(封装、抽象、继承、多态)的编程语言。

就是将对象或类作为代码组织的基本单元,经常会遇到 is-a 这种类关系(比如狗是一种动物),

UML

那就是 UML(Unified Model Language),统一建模语言
实际上,UML 是一种非常复杂的东西。它不仅仅包含我们常提到类图,还有用例图、顺序图、活动图、状态图、组件图等。在我看来,即便仅仅使用类图,学习成本也是很高的。就单说类之间的关系,UML 就定义了很多种,比如泛化、实现、关联、聚合、组合、依赖等。要想完全掌握,并且熟练运用这些类之间的关系,来画 UML 类图,肯定要花很多的学习精力。而且,UML 作为一种沟通工具,即便你能完全按照 UML 规范来画类图,可对于不熟悉的人来说,看懂的成本也还是很高的。所以,从我的开发经验来说,UML 在互联网公司的项目开发中,用处可能并不大。为了文档化软件设计或者方便讨论软件设计,大部分情况下,我们随手画个不那么规范的草图,能够达意,方便沟通就够了,而完全按照 UML 规范来将草图标准化,所付出的代价是不值得的。

面向过程

一个例子进一步解释一下。假设我们有一个记录了用户信息的文本文件 users.txt,每行文本的格式是 name&age&gender(比如,小王 &28& 男)。我们希望写一个程序,

  • 从 users.txt 文件中逐行读取用户信息,
  • 然后格式化成 name\tage\tgender(其中,\t 是分隔符)这种文本格式,
  • 并且按照 age 从小到大排序之后,
  • 重新写入到另一个文本文件 formatted_users.txt 中。

针对这样一个小程序的开发,我们一块来看看,用面向过程和面向对象两种编程风格,编写出来的代码有什么不同。首先,我们先来看,用面向过程这种编程风格写出来的代码是什么样子的。注意,下面的代码是用 C 语言这种面向过程的编程语言来编写的。

  1. struct User {
  2. char name[64];
  3. int age;
  4. char gender[16];
  5. };
  6. struct User parse_to_user(char* text) {
  7. // 将text(“小王&28&男”)解析成结构体struct User
  8. }
  9. char* format_to_text(struct User user) {
  10. // 将结构体struct User格式化成文本("小王\t28\t男")
  11. }
  12. void sort_users_by_age(struct User users[]) {
  13. // 按照年龄从小到大排序users
  14. }
  15. void format_user_file(char* origin_file_path, char* new_file_path) {
  16. // open files...
  17. struct User users[1024]; // 假设最大1024个用户
  18. int count = 0;
  19. while(1) { // read until the file is empty
  20. struct User user = parse_to_user(line);
  21. users[count++] = user;
  22. }
  23. sort_users_by_age(users);
  24. for (int i = 0; i < count; ++i) {
  25. char* formatted_user_text = format_to_text(users[i]);
  26. // write to new file...
  27. }
  28. // close files...
  29. }
  30. int main(char** args, int argv) {
  31. format_user_file("/home/zheng/user.txt", "/home/zheng/formatted_users.txt");
  32. }

vs——面向对象

  1. public class User {
  2. private String name;
  3. private int age;
  4. private String gender;
  5. public User(String name, int age, String gender) {
  6. this.name = name;
  7. this.age = age;
  8. this.gender = gender;
  9. }
  10. public static User praseFrom(String userInfoText) {
  11. // 将text(“小王&28&男”)解析成类User
  12. }
  13. public String formatToText() {
  14. // 将类User格式化成文本("小王\t28\t男")
  15. }
  16. }
  17. public class UserFileFormatter {
  18. public void format(String userFile, String formattedUserFile) {
  19. // Open files...
  20. List users = new ArrayList<>();
  21. while (1) { // read until file is empty
  22. // read from file into userText...
  23. User user = User.parseFrom(userText);
  24. users.add(user);
  25. }
  26. // sort users by age...
  27. for (int i = 0; i < users.size(); ++i) {
  28. String formattedUserText = user.formatToText();
  29. // write to new file...
  30. }
  31. // close files...
  32. }
  33. }
  34. public class MainApplication {
  35. public static void main(String[] args) {
  36. UserFileFormatter userFileFormatter = new UserFileFormatter();
  37. userFileFormatter.format("/home/zheng/users.txt", "/home/zheng/formatted_users.txt");
  38. }
  39. }

1.OOP 更加能够应对大规模复杂程序的开发

  1. 但对于大规模复杂程序的开发来说,整个程序的处理流程错综复杂,并非只有一条主线。如果把整个程序的处理流程画出来的话,会是一个网状结构。如果我们再用面向过程编程这种流程化、线性的思维方式,去翻译这个网状结构,去思考如何把程序拆解为一组顺序执行的方法,就会比较吃力。这个时候,面向对象的编程风格的优势就比较明显了<br />除此之外,面向对象编程还提供了一种更加清晰的、更加模块化的代码组织方式。比如,我们开发一个电商交易系统,业务逻辑复杂,代码量很大,可能要定义数百个函数、数百个数据结构,那如何分门别类地组织这些函数和数据结构,才能不至于看起来比较凌乱呢?类就是一种非常好的组织这些函数和数据结构的方式,是一种将代码模块化的有效手段。

2.OOP 风格的代码更易复用、易扩展、易维护

定义数据和方法分离的类—其实是面向过程

我们再来看最后一种面向对象编程过程中,常见的面向过程风格的代码。那就是,数据定义在一个类中,方法定义在另一个类中。你可能会觉得,这么明显的面向过程风格的代码,谁会这么写呢?实际上,如果你是基于 MVC 三层结构做 Web 方面的后端开发,这样的代码你可能天天都在写。传统的 MVC 结构分为 Model 层、Controller 层、View 层这三层。不过,在做前后端分离之后,三层结构在后端开发中,会稍微有些调整,被分为 Controller 层、Service 层、Repository 层。Controller 层负责暴露接口给前端调用,Service 层负责核心业务逻辑,Repository 层负责数据读写。而在每一层中,我们又会定义相应的 VO(View Object)、BO(Business Object)、Entity。一般情况下,VO、BO、Entity 中只会定义数据,不会定义方法,所有操作这些数据的业务逻辑都定义在对应的 Controller 类、Service 类、Repository 类中。这就是典型的面向过程的编程风格。实际上,这种开发模式叫作基于贫血模型的开发模式,也是我们现在非常常用的一种 Web 项目的开发模式。

why 我们容易写出面向过程的代码

在生活中,你去完成一个任务,你一般都会思考,应该先做什么、后做什么,如何一步一步地顺序执行一系列操作,最后完成整个任务。面向过程编程风格恰恰符合人的这种流程化思维方式。而面向对象编程风格正好相反。它是一种自底向上的思考方式。它不是先去按照执行流程来分解任务,而是将任务翻译成一个一个的小的模块(也就是类),设计类之间的交互,最后按照流程将类组装起来,完成整个任务。我们在上一节课讲到了,这样的思考路径比较适合复杂程序的开发,但并不是特别符合人类的思考习惯。