前言

学习设计模式,需要了解面向对象思想。利用面向对象思想的特性,能够帮助我们设计出优秀的程序。


面向过程思想

特点

  • 关注点:正在发生的过程
  • 事情的发生按照一定的“逻辑时间顺序”
  • 符合多数人思考、计算机处理问题的逻辑

示例(C++语言描述)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include <iostream>
using namespace std;

int main()
{
//定义并初始化变量
int num1 = 1; //操作数1
char oper = '+'; //计算符
int num2 = 2; //操作数2
int result = 0; //计算结果

//判定并计算
switch (oper)
{
case '+':
result = num1 + num2;
break;
case '-':
result = num1 - num2;
break;
default:
break;
}

cout << result << endl; //输出计算结果

return 0;
}

程序定义并初始化变量,然后进行判断计算,最后输出结果。程序的执行“从上至下”(按照语句顺序),“从过去到未来”(按照时间顺序)经历一定的过程。

缺点

  • 维护性差
  • 复用性差
  • 扩展性差
  • 灵活性差

优秀程序设计的四个特性

在实际业务、服务开发中,需求变化,程序就要修改。优秀程序设计旨在用更短的时间、变动更少的代码、按一定设计步骤有序无差错地完成任务。

  • 维护性:只修改相关代码/功能,而不影响其他代码/功能
  • 复用性:代码/功能可重复使用
  • 扩展性:能在原有代码/功能基础上,增添新的代码/功能
  • 灵活性:代码/功能适用于多种场景

面向对象思想

关注点:正在受影响的对象
三大特性:封装,继承,多态

封装

目的

  • 拆分逻辑
  • 降低耦合度
  • 隐藏实现细节

示例(C++语言描述)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#include <iostream>
using namespace std;

//计算类
class Operation
{
public:
int num1; //操作数1
char oper; //计算符
int num2; //操作数2
int result; //计算结果

//计算方式
void calculate()
{
switch (oper)
{
case '+':
result = num1 + num2;
break;
case '-':
result = num1 - num2;
break;
default:
break;
}
}
};

int main()
{
//创建并初始化计算类的对象
Operation operation;
operation.num1 = 1;
operation.oper = '+';
operation.num2 = 2;

operation.calculate(); //计算

cout << operation.result << endl; //输出计算结果

return 0;
}

程序定义了一个计算类,将”操作数、操作符、计算结果和计算方式”逻辑相似且共同实现一种功能的“实体”封装;在主函数中将计算的业务逻辑和输出显示的界面的代码逻辑拆分,修改代码可选择只修改其中一部分而不影响另一部分,耦合度降低;对主函数而言,计算类的实现细节是隐藏的,主函数只需知道如何调用,可以将计算类复用在其他位置。

继承和多态

目的

  • 拆分逻辑
  • 降低耦合度

当需要修改计算类时,仍然存在耦合度高的问题。例如想为其增添“乘法计算”功能,则需在“calculate()”函数的“switch”语句中添加代码,可能会错误修改“加法、减法计算”功能的代码。

示例(C++语言描述)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
#include <iostream>
using namespace std;

//计算类
class Operation
{
public:
int num1; //操作数1
char oper; //计算符
int num2; //操作数2
int result; //计算结果

virtual void calculate() = 0; //纯虚函数
};

//计算加法类
class Operation_add : public Operation //继承
{
void calculate() //重载 多态
{
result = num1 + num2;
}
};

//计算减法类
class Operation_sub : public Operation
{
void calculate()
{
result = num1 - num2;
}
};

//计算乘法类
class Operation_mul : public Operation
{
void calculate()
{
result = num1 * num2;
}
};

/**
* 程序设计思路:依据给定的计算符,创建计算类相应的子类对象,调用子类的方法计算
* 使用简单工厂模式
*/
//计算工厂类
class Operation_factory
{
public:
static Operation *create_operation(char oper) //静态函数
{
Operation *operation = NULL; //指向计算类的指针

//依据给定的计算符,创建计算类相应的子类
switch (oper)
{
case '+':
operation = new Operation_add();
break;
case '-':
operation = new Operation_sub();
break;
case '*':
operation = new Operation_mul();
break;
default:
break;
}

return operation; //返回相应的计算子类对象
}
};

int main()
{
//依据给定的计算符,创建计算类相应的子类对象并初始化
Operation *operation = Operation_factory::create_operation('+');
//静态函数属于类而不是对象,由类直接调用
operation->num1 = 1;
operation->num2 = 2;

operation->calculate(); //计算

cout << operation->result << endl; //输出计算结果

return 0;
}

通过继承,将“计算”的各个“子功能”逻辑拆分,每个功能单独成一“类”,耦合度降低;通过多态,将函数重载以实现不同的计算。当再想增加一个“除法计算”功能时,只需增加一个计算除法子类,并在计算工厂类的“switch”语句中增加一个创建计算除法子类对象的分支,而不会“触碰”/误修改到“加、减和乘法计算”功能的代码,提高了程序的维护性


总结

  • 面向过程的关注点:正在发生的过程
  • 优秀程序设计的四大特性:维护性,复用性,扩展性,灵活性
  • 面向对象的关注点:正在受影响的对象
  • 三大特性:封装,继承,多态

作者的话

  • 文章内容基于读者有一定程序设计基础,了解面向过程、对象思想等一定知识,主要目的是对知识的串讲、延拓,详细概念理解请参阅其他资料
  • 文章内容示例简单,思想优越性的体现可能不理想。当拓展到大型业务、服务和程序时,务须具备高效的设计思想、使用良好的设计模式编程
  • 文章在描述时有疑惑的地方,请留言,必会一一耐心讨论、解答
  • 文章在认识上有错误的地方, 敬请批评指正
  • 望读者们都能有所收获

参考资料

《大话设计模式》作者:程杰