面向对象是怎样工作的-终极浓缩篇

面向对象是怎样工作的-终极浓缩篇
🖥️ 面向对象的工作原理
“面向对象是一种强大的编程范式,能够通过将数据和方法封装在对象中,提供更高的可重用性和可维护性。”

面向对象的基本概念
面向对象编程(Object-Oriented Programming,OOP)的核心思想包括:

类(Class):定义对象的蓝图,包含属性和方法。
实例(Instance):类的具体实现,表示对象的具体存在。
封装(Encapsulation):将数据和操作数据的方法封装在对象内部,限制外部直接访问。
继承(Inheritance):允许新类继承已有类的属性和方法,促进代码复用。
多态(Polymorphism):同一操作可以作用于不同的对象,提升灵活性。
面向对象的优势
优势 描述
可重用性 通过继承和类库,减少重复代码,提高开发效率。
可维护性 封装和模块化使得代码更容易理解和修改。
灵活性 通过多态,可以在运行时决定使用哪个对象的方法。
易于扩展 新功能可以通过添加新类和修改少量代码实现。
面向对象编程的历史
面向对象编程并非一蹴而就,而是随着编程语言的发展逐步演变的。
从最初的机器语言到汇编语言,再到高级语言和结构化编程,OOP是对以往技术的延续和提升。
面向对象编程的结构
三大要素
类的功能:类可以汇总数据、隐藏实现细节、创建多个实例。
多态:同一方法可以在不同类中实现。
继承:允许新类重用父类的属性和方法。
结构化语言的演进
结构化编程强调可维护性,通过限制全局变量和减少GOTO语句来实现。
OOP进一步提升了这些概念,强调通过对象组织代码。
记忆结构与运行机制
编译器与解释器:编译器将源代码转化为机器代码,解释器逐行执行代码。
内存管理:
静态区:存放固定数据。
堆区:动态分配内存用于对象实例。
栈区:用于存放方法调用的局部变量和返回地址。
重用技术
技术类型 描述
类库 提供通用功能的集合,促进代码复用。
框架 为特定类型的应用程序提供的可复用结构和工具。
组件 独立的可重用单元,通常具有明确的接口。
设计模式 解决特定设计问题的最佳实践和方案。
归纳整理法
面向对象不仅仅是编程技术,也是对现实世界的一种抽象方法。
通过清晰的职责分配和建模,可以更有效地将现实问题转化为软件解决方案。
要掌握的关键技术
UML(统一建模语言):用于可视化设计和建模。
敏捷开发:强调迭代和快速反馈的开发方法。
通过对面向对象的深入理解和实践,开发者能够在复杂的软件项目中提高开发效率和软件质量。

📚 面向对象:让软件开发变轻松的技术

  1. 面向对象的基本概念
    面向对象的定义
    面向对象(Object Oriented)是一种软件开发的综合技术,旨在通过“以对象为中心”的方式来简化软件的开发和维护。

面向对象的目标是“能够轻松地进行较难的软件开发的综合技术”。

面向对象的技术领域
面向对象技术涵盖了以下几个方面:

编程语言(如 Java、Python 等)
需求规格说明书
设计内容的图形表示
可重用的软件构件群
业务分析和需求定义方法
2. 面向对象的重要性
为什么要使用面向对象
简化开发:面向对象技术使软件的维护和重用变得更加容易。
提高独立性:通过提高构件的独立性,修改时影响范围最小化,便于重用。
3. 面向对象的结构
OOP 结构的复杂性
面向对象编程(OOP)引入了许多结构,如类、实例、继承、多态等,这些结构增加了学习的复杂性。

OOP 结构 描述
类 对象的蓝图,定义对象的属性和方法
实例 类的具体实现
继承 子类继承父类的属性和方法
多态 不同类的对象可以以相同的方式调用方法
面向对象的比喻
使用比喻可以帮助理解 OOP 结构,但过于依赖比喻可能导致混淆。

“动物是超类,哺乳类和鱼类是子类。” 这种比喻虽然形象,但可能不够准确。

  1. 面向对象的抽象
    面向对象的抽象性
    面向对象的概念较为抽象,涉及的对象可以是现实世界中的人、组织、事件等。

面向对象思想的应用已扩展至需求定义、业务分析等领域。

  1. 面向对象的学习难点
    主要难点
    结构复杂:OOP 的结构比传统编程语言复杂,需要时间理解。
    比喻滥用:比喻的误用可能导致对 OOP 结构的误解。
    抽象概念:面向对象的抽象概念可能让学习者感到困惑。
  2. 本书的构成
    内容安排
    本书分为两部分:

前半部分:介绍面向对象的编程技术(第2章到第6章)。
后半部分:介绍面向对象的应用技术(第7章到第11章)。
章节 内容
第2章 面向对象与现实世界的关系
第3章 OOP 的基本结构
第4章 OOP 运行时机制
第5章 可重用构件群与设计模式
第6章 UML(统一建模语言)
第7章 归纳整理法的应用
第8章 UML 的使用方法
第9章 业务分析与需求定义
第10章 面向对象设计
第11章 敏捷开发方法
目标
本书旨在用清晰的逻辑介绍面向对象所涉及的各项技术,并帮助读者理解其重要性与应用。

🐶 面向对象的基本概念

  1. 面向对象的三大要素
    1.1 类与实例
    类(class):面向对象的基本结构,表示类型或种类。
    实例(instance):具体的物,属于某个类。类是一个集合,而实例是集合中的元素。
    类 (class) 实例 (instance)
    狗(Dog) 斑点狗、柴犬
    国家(Country) 中国、日本、韩国、美国、英国
    歌手(Singer) 迈克尔·杰克逊、矢泽永吉
    1.2 面向对象编程中的类定义
    在面向对象编程中,我们通过定义类来编写程序。在程序运行时,从定义的类创建实例,通过它们之间的交互来实现软件的功能。

java
Copy
// 狗类的定义
class Dog {
String name; // 名称
Dog(String name) { // 构造函数
this.name = name;
}
String cry() { // 发出叫声的方法
return “汪”;
}
}
2. 多态的概念
2.1 多态(polymorphism)
多态的含义是“变为各种形式”。在面向对象中,多态允许不同类的实例对同一消息作出响应。
示例代码
java
Copy
// 创建两只狗
Dog pochi = new Dog(“斑点狗”);
Dog taro = new Dog(“柴犬”);

System.out.println(pochi.cry()); // 输出“汪”
System.out.println(taro.cry()); // 输出“汪”
2.2 消息传递
调用方法的过程可以看作是向对象发送消息。在上面的例子中,调用cry()方法就像是向狗发出“叫”的指示。

  1. 继承的概念
    3.1 继承
    继承是一种整理物的类型共同点和不同点的结构。通过继承,可以避免重复定义相似的类。
    示例代码
    java
    Copy
    class Animal { // 动物类
    abstract String cry(); // 定义叫声的抽象方法
    }

class Baby extends Animal { // 婴儿类
String cry() {
return “哇”; // 婴儿的叫声
}
}

class Dog extends Animal { // 狗类
String cry() {
return “汪”; // 狗的叫声
}
}

class Crow extends Animal { // 乌鸦类
String cry() {
return “呱”; // 乌鸦的叫声
}
}
3.2 教练类示例
java
Copy
class Trainer { // 教练类
void execute(Animal animal) { // 参数是动物
System.out.println(animal.cry()); // 让动物叫
}
}
4. 面向对象与现实世界的关系
4.1 类与实例的差异
在现实世界中,实例是先存在的,然后我们根据观察进行分类。而在面向对象中,类是用来创建实例的结构。
4.2 消息传递的不同
在现实世界中,生物的行为是自主的,不一定遵循指示。而在面向对象中,所有动作必须通过方法来实现。
5. 结论
面向对象并不直接表示现实世界,而是为了解决软件开发中的复杂性和提高可维护性、可重用性而设计的结构。理解这些概念有助于更好地掌握面向对象编程。
📜 理解OOP:编程语言的历史

  1. 编程语言的演变
    1.1 高级语言的出现
    高级语言如COBOL和FORTRAN在1950年代和1960年代出现,提高了编程的效率和质量。
    尽管计算机技术迅速发展,软件需求的增加导致了“软件危机”的出现。
    1.2 结构化编程
    结构化编程是由荷兰计算机科学家戴克斯特拉(Dijkstra)提出的,其基本思想是采用简单易懂的结构来编写程序,以确保程序的正确性。

三种基本结构:
循序:按照顺序执行命令
选择:根据条件判断执行不同命令(如if语句)
重复:在特定条件下重复执行命令(如for和while语句)
基本结构 描述
循序 按顺序执行命令
选择 根据条件判断执行不同命令
重复 在条件成立期间重复执行命令
结构化编程也称为无GOTO编程,因为它提倡废除难以理解的GOTO语句。

1.3 子程序的独立性
子程序(subroutine)在程序中重复出现的命令被汇总到一处,以提高效率。
为了提高可维护性,减少共享信息,采用局部变量和按值传递(call by value)的方法。
特征 描述
局部变量 只在子程序内使用,调用结束后消失
按值传递 复制参数值传递,不影响调用端的变量
2. 结构化语言的进化
2.1 结构化语言的代表
ALGOL、Pascal和C语言是结构化语言的典型代表。
这些语言支持明确的控制结构并提升了程序的可维护性。
2.2 C语言的特点
C语言支持结构化编程,允许位运算和高效的内存管理。
C语言的功能通过函数库实现,而不是语言规范直接提供。
3. 编程语言的进化方向
3.1 重视可维护性和可重用性
编程语言从机器语言演进至高级语言和结构化语言,目标是提高可维护性和可重用性。
20世纪末的“计算机2000年问题”显示了程序寿命的延长和对可维护性的重视。
4. 结构化编程未解决的问题
4.1 全局变量和可重用性
结构化编程未完全解决全局变量问题,全局变量的修改需遍历所有逻辑,影响范围难以确定。
可重用性差,虽然有公用子程序,但整体效果微小。
OOP(面向对象编程)作为解决这些问题的方式,逐渐成为主流。

  1. OOP的基本结构
    5.1 OOP的三大要素
    类、继承、多态是OOP的核心结构,它们提供了去除冗余和进行整理的能力。
    OOP的结构解决了全局变量和可重用性的问题。
    OOP要素 作用
    类 将相关的子程序和变量汇总,形成大粒度构件
    继承 允许创建新类以复用已有类的功能
    多态 处理不同数据类型的一致接口
    通过这些结构,程序员能够更好地管理复杂性,提高代码的可维护性和重用性。

🖥️ 面向对象编程基础
“面向对象编程(OOP)是基于对象的编程范式,通过在对象中封装数据和方法来简化复杂性。”

OOP 的基本概念
OOP 的语言
不同的编程语言在面向对象编程(Object-Oriented Programming, OOP)的实现上有所不同。以下是一些常见的 OOP 语言:

Java
Python
Ruby
PHP
C#
JavaScript
Visual Basic.NET
C++
Smalltalk
“尽管它们都属于面向对象编程,但功能和语法并不相同。”

类的功能
在 OOP 中,类是构建块,它具有以下三种基本功能:

汇总
隐藏
创建多个实例
4.3 类的功能之一:汇总
汇总的价值
类能够将变量和方法(子程序)进行汇总:

汇总:将多个子程序和变量放在一起。
隐藏:只允许类内部使用的变量和子程序。
创建多个实例:能够从一个类创建多个对象。
示例代码:结构化编程的文件访问处理
以下是结构化编程的文件访问处理示例:

java
Copy
// 存储正在访问的文件编号的全局变量
int fileNum;

// 打开文件的子程序
void openFile(String pathName){ /* 省略逻辑处理*/ }

// 关闭文件的子程序
void closeFile() { /* 省略逻辑处理*/ }

// 从文件读取一个字符的子程序
char readFile() { /* 省略逻辑处理*/ }
使用类进行汇总的示例
以下是使用类进行汇总的示例代码:

java
Copy
class TextFileReader {
// 存储正在访问的文件编号的变量
int fileNum;

// 打开文件
void open(String pathName) { /* 省略逻辑处理*/ }

// 关闭文件
void close() { /* 省略逻辑处理*/ }

// 从文件读取一个字符
char read() { /* 省略逻辑处理*/ }
}
汇总的比喻
“类的汇总功能可以比作整理房间,多个箱子分别存放不同物品,使得查找物品更加方便。”

汇总的效果
效果 描述
构件数量减少 通过汇总,类的总数可显著减少。
方法命名轻松 在类中,方法名称仅需在类内唯一。
方法查找更容易 汇总后的方法更容易被查找和重用。
4.4 类的功能之二:隐藏
隐藏的必要性
在类中,某些变量(如 fileNum)不应被外部访问,因此需要进行访问限制。通过将变量声明为 private,可以实现这一点:

java
Copy
class TextFileReader {
// 存储正在访问的文件编号的变量
private int fileNum;
// 打开文件
void open(String pathName) { /* 省略逻辑处理*/ }
// 关闭文件
void close() { /* 省略逻辑处理*/ }
// 从文件读取一个字符
char read() { /* 省略逻辑处理*/ }
}
隐藏的优势
“通过隐藏变量和方法,我们能够控制对它们的访问,从而提高程序的安全性和可维护性。”

4.6 类的功能之三:创建多个实例
实例的概念
在 OOP 中,通过类可以创建多个实例,每个实例都可以独立地维护自己的状态。这使得处理多个相似对象变得简单。

创建实例的示例
java
Copy
// 从 TextFileReader 类创建两个实例
TextFileReader reader1 = new TextFileReader();
TextFileReader reader2 = new TextFileReader();
reader1.open(“C:\aaa.txt”); // 打开第一个文件
reader2.open(“C:\bbb.txt”); // 打开第二个文件
实例的优势
通过实例化,可以处理多个同类对象而不需要担心变量冲突。

特性 描述
独立状态 每个实例都有自己独立的状态和行为。
简化代码 可以避免使用数组等复杂结构来管理多个对象。
4.7 实例变量是限定访问范围的全局变量
实例变量结合了局部变量和全局变量的优点,即能够限定访问范围,同时在实例被创建后一直保留。

变量类型 访问范围 存在期间
局部变量 仅在特定子程序内访问 子程序调用期间
全局变量 程序的任何位置都可以访问 应用程序运行期间
实例变量 仅能在同一类内部访问 从实例创建到不再需要
4.8 三大要素之二:实现调用端公用化的多态
多态的定义
多态(Polymorphism)是指同一操作可以作用于不同的对象,能够通过统一的接口来操作不同的对象。

多态的应用示例
创建一个读取网络数据的类 NetworkReader,与 TextFileReader 共享相同的调用方式。

java
Copy
public class NetworkReader {
public void open() { /* 省略逻辑处理*/ }
public void close() { /* 省略逻辑处理*/ }
public char read() { /* 省略逻辑处理*/ }
}
多态的优势
通过多态,可以在不修改调用端的情况下增加新的被调用端。这种灵活性使得程序更加可扩展。

优势 描述
灵活性 可以在不修改现有代码的情况下扩展功能。
代码重用 通过统一的接口,减少了重复代码的编写。
以上是对 OOP 的三大要素——类的汇总、隐藏和创建多个实例的介绍。

🐍 面向对象编程技术:去除冗余、进行整理
📚 输入字符串的方法
输入字符串的方法可以通过不同的调用端实现,包括控制台输入、文件输入和网络输入。
图4-7展示了利用多态(polymorphism)来确保扩展性。
🏛️ 继承的概念
继承是“将类的共同部分汇总到其他类中的结构”,是面向对象编程(OOP)的三大要素之一。

继承的结构
超类(superclass)与子类(subclass)之间的关系:
子类只需声明继承,即可定义超类中的所有变量和方法。
图4-8展示了继承的结构。
继承的优势
通过创建公用类来汇总变量和方法,能够去除重复定义的类。
在面向对象编程中,超类为公用类,使用超类的类为子类。
方法调用的一致性
在声明继承的子类中,继承的方法的参数和返回值类型必须与超类一致。
图4-9展示了继承与多态的关系。
📝 OOP 三大要素总结
三大要素 说明 目的 记法
类 汇总子程序和变量,创建软件构件 整理 汇总、隐藏和“创建很多个”的结构
多态 实现方法调用端的公用化 去除冗余 创建公用主程序的结构
继承 实现重复的类定义的公用化 去除冗余 将类的共同部分汇总到另外一个类中的结构
🔄 嵌入类型与类型检查
嵌入类型(embedded types)可以使程序员的工作变轻松。
在程序中定义变量时,指定类型(如整型、浮点型等)是为了告诉编译器内存大小和防止错误。
OOP 允许程序员将自定义类作为类型使用,这种结构可以进行类型检查。
类型检查
类型检查分为静态类型(static typing)和动态类型(dynamic typing)两种方式:
静态类型:在程序编译时检查错误(如Java、C#)。
动态类型:在程序运行时检查错误(如Python、Ruby)。
⚠️ 异常处理
异常用于处理特殊错误,不同于传统的返回值方式。
异常结构允许在方法中声明可能返回特殊错误,提升了错误处理的效率。
♻️ 垃圾回收
垃圾回收(Garbage Collection, GC)是由系统自动进行的内存管理,帮助开发者避免内存泄漏和错误的删除操作。
📦 包的结构
包是进行类的汇总的容器,避免类名冲突并创建层次结构。
图4-11展示了包的结构,类似于文件系统中的目录。
🧩 OOP 的进化
OOP 是对传统编程技术的补充,导入了许多独特的结构,如类、多态、继承等。
这些结构帮助提升程序的可维护性和可重用性。
🔍 更先进的 OOP 结构
包、异常和垃圾回收等是现代编程语言中进一步提升OOP功能的结构。
🧭 结论
OOP 是为了提高程序质量与可维护性而设计的,程序员需要合理使用OOP的结构。希望大家在编写程序时,能够充分利用这些面向对象的技术,以提高软件的质量和可维护性。
🧠 理解内存结构:程序员的基本素养

  1. 内存区域的划分
    内存区域可分为以下三部分:

区域类型 特征描述
静态区 从程序开始运行时分配,存在于程序结束前。存储全局变量和代码信息。
堆区 动态分配的内存区域,根据应用程序的请求进行管理。主要用于存储实例。
栈区 用于线程控制的内存区域,每个线程都有自己的栈区,存储子程序的参数和局部变量。
静态区
静态区是从程序开始运行时产生的,信息配置在程序运行时不会发生变化。

堆区
堆区是程序运行时动态分配的内存区域,适用于需要在运行时分配和释放内存的场景。

栈区
栈区采用后进先出(LIFO)方式存储信息,适合存储子程序调用的参数和局部变量。

  1. 编译器与解释器的运行方式
    程序的基本运行方式有两种:

方式 特征描述
编译器方式 将源代码整体转换为机器语言后运行。优点:运行效率高;缺点:编译时间长。
解释器方式 一边解释源代码一边运行。优点:可立即运行,兼容性好;缺点:运行速度慢。
编译器方式
将程序中的命令一次性转换为机器语言,直接执行,运行速度快。

解释器方式
逐行解释并运行源代码,能够及时发现语法错误,但运行速度较慢。

  1. 中间代码方式
    中间代码方式结合了编译和解释的优点:

首先用编译器将源代码转换为中间代码,然后使用解释器将中间代码转换为机器语言执行。

  1. 线程与并发处理
    线程
    线程是程序的运行单位,多个线程可以在同一进程中并发运行。

并发处理
CPU 通过快速切换线程,使多个线程看似同时执行,从而提高处理效率。

  1. 使用静态区、堆区和栈区进行管理
    内存的管理方式对程序性能有重大影响。以下是三种内存区域的特征:

区域类型 用法 存储信息 分配单位
静态区 应用程序开始时分配 全局变量、代码信息 整个应用程序
堆区 根据应用程序需求分配 任意(取决于应用程序) 系统或应用程序
栈区 后进先出存储 子程序的参数、局部变量和返回位置 每个线程
6. OOP 的内存使用方法
在面向对象编程(OOP)中,内存使用方式与传统编程语言大相径庭。OOP 程序的主要特征是实例的创建和内存管理。

实例与指针
在OOP中,创建的实例存储在堆区,而变量中存储的是实例的指针。

  1. 注意事项:复制存储实例的变量
    在复制变量时需要注意,若不小心可能会引起难以察觉的错误。以下是一个简单的示例:

java
Copy
class Person {
private String name;
public void setName(String nm) {
this.name = nm;
}
public String getName() {
return this.name;
}
}
在编程中,确保理解变量存储的实际内容与指针的使用是至关重要的。

💻 理解内存结构:程序员的基本素养
实例创建与指针赋值
代码清单5.3:给 Person 设置姓名
java
Copy
Person musician = new Person(); // (1) 创建 Person 实例
Person john = musician; // (2) 赋给变量 john
john.setName(“John”); // (3) 给变量 john 设置姓名
Person paul = musician; // (4) 赋给变量 paul
paul.setName(“Paul”); // (5) 给变量 paul 设置姓名
输出姓名的操作
java
Copy
System.out.println(john.getName()); // 输出变量 john 的姓名
System.out.println(paul.getName()); // 输出变量 paul 的姓名
结果
输出结果为:

text
Copy
Paul
Paul
现象分析
由于变量 john 和 paul 都指向同一个 Person 实例,因此修改其中一个变量的属性会影响到另一个变量的输出结果。

内存状态与指针的关系
内存状态示意图
在 (1) 处,创建 Person 实例并将其指针存储到变量 musician 中。

堆区:Person 实例(姓名为空)
变量:john, paul, musician
在 (2) 处,将 musician 的内容赋给 john,在 (3) 处设置姓名为“John”。

堆区:Person 实例(姓名为“John”)
变量:john, paul, musician
代码清单5.3 运行结果的分析
在 (2) 处进行的赋值操作仅仅是复制了 Person 实例的指针,而不是创建了新的实例。
因此,修改 paul 的姓名为“Paul”后,john 的姓名也变为了“Paul”。
正确设置实例姓名的方式
代码清单5.6:正确地设置 Person 实例的姓名
java
Copy
Person john = new Person(); // 创建 Person 实例
john.setName(“John”); // 给变量 john 设置姓名
Person paul = new Person(); // 创建 Person 实例
paul.setName(“Paul”); // 给变量 paul 设置姓名
内存状态示意图
这样,john 和 paul 分别指向不同的 Person 实例:
堆区:Person 实例(姓名为“John”) 和 Person 实例(姓名为“Paul”)
存储指针与实例的理解
重要概念
在 Java 中,变量中存储的并不是实例本身,而是实例的指针。
当将存储实例的变量赋给其他变量时,只是复制指针,堆区中的实例本身并不会发生变化。
垃圾回收机制
垃圾回收的执行
垃圾回收器是专用程序,负责删除堆区中不再需要的实例。
垃圾回收的判断标准是“发现孤立的实例”。
孤立实例的定义
孤立实例是指从根部(栈区和方法区)无法到达的实例。
垃圾回收的示意
垃圾回收的工作机制可以形象地比喻为“垃圾回收器大魔王找到与谁都没有‘拉手’的实例,并将其当场清除”。
继承与内存配置
代码清单5.7:Employee 类
java
Copy
class Employee extends Person { // Employee 类(继承 Person 类)
private int employeeNum; // 持有员工编号的实例变量
public void setEmployeeNum(int empNum) { /* 省略逻辑处理 / }
public int getEmployeeNum() { /
省略逻辑处理 */ }
}
内存配置说明
子类可以直接使用超类中定义的方法,方法区中存储的代码信息也可以被直接使用。
实例变量的定义被复制到子类中,但实际的值根据实例的不同而有所不同。
类型 描述
方法 子类中可以直接调用超类的方法
实例变量 子类的实例都会持有超类中定义的实例变量
关键点总结
在 Java 中,实例的指针而非实例本身被存储在变量中。
垃圾回收机制会自动处理不再需要的实例,重要的是理解孤立实例的概念。
继承带来的方法和实例变量在内存中的配置是不同的,掌握这些知识是程序员的基本素养。
📚 OOP中的可重用技术
6.1 OOP的优秀结构能够促进重用
“本章将介绍OOP带来的两种可重用技术。”

可重用技术的两种类型
软件重用:准备通用性强的软件构件群进行重用,例如类库、框架和组件。
思想或技术窍门的重用:对软件开发或维护过程中频繁出现的固定手法进行命名,形成模式。
OOP的目的
提高软件的可维护性和可重用性。
利用类、多态和继承等结构实现重用。
可重用构件群与设计模式的发展历程
步骤 说明
(1) 利用OOP创建可重用构件群
(2) 提取共同的设计思想,形成设计模式
(3) 利用设计模式创建新的可重用构件群
6.2 类库是OOP的软件构件群
类库的定义
类库(library class):OOP结构中的“类”的集合,提供通用功能。
传统的类库被称为“函数库”或“公共子程序库”。
使用方式的进步
与传统的函数库相比,OOP的类库允许:

从类库创建实例,使用方法和变量定义。
利用多态替换类库调用的逻辑。
利用继承向类库中的类添加方法和变量定义。
类库的处理流程
处理方式 描述
利用类 从类库中的类创建实例
利用多态 替换类库调用逻辑为应用程序固有处理
利用继承 向类库中的类添加新的方法和变量定义
6.3 标准类库是语言规范的一部分
标准类库:编程语言附带的类库,提供不依赖于特定应用程序的通用功能。
Java中的标准类库
包含字符串操作、算术计算、文件访问等多种功能,是语言规范的一部分。
6.4 将Object类作为祖先类的继承结构
Object类:所有类的超类,Java中最顶端的类。
Java的Object类主要方法
方法名 说明
clone() 创建对象的副本
equals() 判断是否与指定对象相等
hashcode() 获取对象的散列值
toString() 获取对象的字符串表示
wait() 暂停正在运行的线程
6.5 框架存在各种含义
框架的定义
框架(framework):可以理解为“结构”或“骨架”,用于软件开发的可重用构件群。
框架的两种情况
总括性的应用程序基础,例如Web应用程序框架。
针对特定目的编写的可重用构件群。
6.6 框架是应用程序的半成品
框架的概念
框架提供基本的控制流程,应用程序通过继承和多态进行调用。
好莱坞原则
“Don’t call us, we will call you” - 表示所有控制流程由框架决定,应用程序的处理在需要时进行调用。

6.7 世界上可重用的软件构件群
类库和框架的质量通常较高,源代码公开,广泛使用。
6.8 独立性较高的构件:组件
组件的定义
组件(component):粒度比OOP的类大,提供二进制形式而非源代码。
组件的应用
如Visual Basic的控件和游戏开发引擎Unity中的组件。
6.9 设计模式是优秀的设计思想集
设计模式的定义
设计模式(design pattern):不依赖于编程语言和应用领域的应用模式。
设计模式的历史
1995年出版的《Design Patterns: Elements of Reusable Object-Oriented Software》引入了GoF设计模式。
GoF设计模式一览
No. 分类 模式名 目的
1 适应设计模式 Iterator 逐个遍历
2 适配器模式 Adapter 加个“适配器”以进行重用
3 模板方法模式 Template Method 将具体处理交给子类
4 工厂方法模式 Factory Method 将实例的生成交给子类
5 单例模式 Singleton 只有一个实例
… … … …
6.10 设计模式是类库探险的路标
设计模式在类库中的应用示例
Java类库中直接使用设计模式名,如Observer、Iterator等。
6.11 扩展到各个领域的思想的重用
设计模式的出现使得在各个领域对技术窍门进行总结和重用的活动普及。
模式技术名称 说明
其他设计模式 限定于特定运行环境和用途的技术窍门集
分析模式 问题领域的模式
架构模式 表示软件整体结构的模式
流程模式 与系统开发的推进相关的模式
反面模式 汇总系统开发中出现的陷阱及对策
6.12 通过类库和模式发现的重用的好处
可重用技术使得开发者可以利用高质量的构件和模式,提升开发效率和软件质量。
💻 面向对象编程与技术
📖 必读书籍推荐
“该书可以说是必读的一本。建议使用JavaEE和.NET开发应用程序系统的工程师务必掌握书中的内容。”

书籍推荐:
《企业应用架构模式》
作者: Martin Fowler
翻译: 王怀民、周斌
出版社: 机械工业出版社,2010年
《Java框架开发入门》
作者: 木村聪
出版社: SoftBank Creative,2010年
🦾 Ruby 编程语言
Ruby 的基础概念
发布年份: 1995年
特性:
将数值和字符串视为类
纯粹的面向对象编程语言
融合函数式语言元素,属于多范式语言
Ruby 示例程序
ruby
Copy
3.times do
puts ‘Hello Ruby!’
end
特点: 代码简洁,没有大括号和分号,易于阅读。
Ruby on Rails
推出年份: 2004年
特征:
用于构建Web应用程序的软件框架
自动生成应用程序的雏形
高开发效率
采用命名约定而非设置文件
Active Record
功能: 动态查询结构
示例方法:
find_by_area
find_by_genre
find_by_area_and_genre
关键概念:
method_missing 方法的使用,动态生成SQL查询。
📊 面向对象的归纳整理法
现实与软件的关系
主要观点: 软件不能直接表示现实世界。
例子: 医院系统、银行系统并不直接映射现实中的医院和银行。
上游工程与业务分析
上游工程: 包括业务分析和需求定义。
面向对象的应用:
提高系统开发的生产率和质量。
类和实例的概念应用于集合论。
🗂️ 集合论与职责分配
集合论
概念: 类用于汇总子程序和变量。
实例: 现实世界中的具体对象(如员工、订单)。
职责分配
消息传递: 指定实例调用类中的方法。
应用示例: 餐厅点菜、建筑公司发活。
📊 UML(统一建模语言)
UML 的定义
功能: 表示软件功能和内部结构的图形绘制方法。
目的: 从庞大的信息中提取重要部分,逻辑清晰且直观。
UML 的图形类型
图形数量: 13种
主要图形及用途:
中文名称 英文名称 用途
类图 Class Diagram 表示类的规格和类之间的关系
复合结构图 Composite Structure Diagram 表示具有整体-部分结构的类的运行时结构
组件图 Component Diagram 表示软件的实现结构
部署图 Deployment Diagram 表示系统的物理结构
对象图 Object Diagram 表示实例之间的关系
包图 Package Diagram 表示包之间的关系
📜 重要概念总结
面向对象的两个方面
编程技术: 关注实现和代码的结构。
归纳整理法: 关注如何将现实世界的事物进行分类和整理。
面向对象的应用范围
包括从业务分析到编程的整个软件开发过程。
📊 UML图形与其用途
UML图形概述
“UML(统一建模语言)是一种用于软件开发的标准化建模语言,它通过图形化的方式表示系统的结构和行为。”

UML图形种类
UML定义了多种图形以满足不同的建模需求,以下是主要的UML图形及其用途:

编号 中文名称 英文名称 用途
1 类图 Class Diagram 表示OOP程序的结构
2 活动图 Activity Diagram 表示一系列处理中的控制流程
3 时序图 Sequence Diagram 将实例之间的相互作用表示为时间序列
4 通信图 Communication Diagram 将实例之间的相互作用表示为组织结构
5 交互概览图 Interaction Overview Diagram 表示根据不同条件执行不同动作的时序图
6 定时图 Timing Diagram 采用带数字刻度的时间轴表示状态迁移
7 用例图 Use Case Diagram 表示系统功能与使用者之间的关系
8 状态机图 State Machine Diagram 表示实例的状态变化
UML的使用方法

  1. 表示OOP程序的结构和动作
    UML可以用来表示面向对象程序设计(OOP)的结构和动作。程序是通过编程语言编写的,而UML通过图形化的方式将程序的结构和动态行为表示出来。

类图的使用
类图是OOP程序的基本单位,表示类及其关系。以下是类图的示例:

类图示例

**节点类(Node)**是一个抽象类,定义了基本属性。
**文件类(File)和目录类(Directory)**是节点类的子类。
通过继承关系和关联关系,类图能够清晰地表达出类之间的结构。
2. 表示程序运行时的动作
UML中的时序图和通信图用于表示程序运行时的动态行为。

时序图
时序图表示实例之间的方法调用顺序,纵轴表示时间,横轴表示实例。示例:

时序图示例

通信图
通信图则关注实例之间的关系,而不是时间顺序。示例:

通信图示例

  1. 表示归纳整理法的成果
    UML还可以用于表示现实世界中分类整理的结果,类图能够有效地表达集合论的关系。

示例:使用类图表示图书分类
使用类图将图书作为全集,中文图书、翻译图书和外文图书作为子集:

图书类结构示例:

图书(Book)
书名(Name)
ISBN
定价(Price)
外文图书(ForeignBook)
折扣价(DiscountPrice)
翻译图书(TranslatedBook)
原书名(OriginalName)
通过类图可以清晰地表示书籍之间的层次关系。

  1. 用例图与活动图
    用例图
    用例图用于明确计算机的工作范围,描述系统与外部用户之间的交互。示例:

用例图示例

活动图
活动图用来描述工作流程,适合表示现实世界中的过程。

总结
UML提供了多种图形工具,使得软件开发中的结构、行为和流程可视化,从而帮助开发者更好地理解和设计系统。通过使用这些图形,开发者可以有效地交流想法、记录设计以及进行系统分析。

📈 状态机图与UML的应用
🗺️ 状态机图的概念
“状态机图是用于表示事物状态根据外部事件而变化的情形,可以用来表示用OOP(面向对象编程)编写的实例的状态迁移、系统整体的状态迁移等各种对象。”

状态机图的基本特征
状态变化:状态机图通过图形化的方式清晰地展示了状态的转移。
外部事件:状态的变化是由外部事件所驱动的。
应用实例:常用于通信等控制系统软件中。
状态机图示例
图8-16:表示购物网站订单的状态迁移,展示了不同状态(如有货、无货、发货完成等)之间的变化。
🖼️ UML图形的分类
用例图
功能:表示交给计算机的工作范围。
活动图
功能:表示现实世界的工作流程。
状态机图
功能:表示外部事件导致的状态变化。
📊 自然语言、计算机语言与建模语言的比较
“UML被称为语言,主要是因为它弥补了自然语言和计算机语言的缺点。”

语言类型 目的 形式 特征
自然语言 人们之间的交流 声音、字符 有基本语法,但比较宽松,允许方言
计算机语言 向计算机指示作业 字符 极其严格
建模语言(UML) 人们之间的交流 图形 重视直观理解
UML的特点
图形表示:UML通过图形化方式提取复杂信息的关键部分,便于理解。
文本描述:同时支持以文本形式进行描述,使用OCL(对象约束语言)。
🛠️ 填补现实世界与软件之间的沟壑
三个阶段的工作
业务分析:整理现实世界工作的推进方法。
需求定义:确定交给计算机的工作范围。
设计:确定软件的编写方法。
工作特点
业务分析:聚焦于理解现实世界的情形。
需求定义:考虑计算机的性质,定义可交由计算机执行的工作。
设计:基于硬件和软件特性,确定软件结构。
📖 业务应用程序的模型
业务应用程序特征
记录现实中的事情:业务应用程序用于支持企业的业务活动,如出货、订货等。
计算能力:能够进行复杂的计算和数据存储,替代人工操作。
图书馆借阅业务建模示例
业务分析
使用活动图表示借阅业务流程,展示用户与图书馆馆员之间的交互。
需求定义
使用用例图表示系统功能,明确计算机需要承担的工作。
概念模型
类图表示管理信息的结构,帮助设计数据库模式。
示例用例图
图9-3:图书馆系统的用例图,展示用户和馆员的基本操作,如搜索藏书、预约借阅等。
📊 结论
UML作为建模语言,能够有效地桥接自然语言与计算机语言之间的缺口,通过图形化的表示方式帮助人们更好地理解和设计复杂的系统。通过状态机图、用例图和活动图等,开发者能够清晰地描绘业务流程和系统状态,为后续的软件开发打下坚实的基础。

📚 业务应用程序与嵌入式软件
业务应用程序的特点
现实世界的记录
“计算机只是记录现实世界中的事情,以供之后参考。”

业务应用程序主要通过计算机实现数据的借阅处理、藏书登记和报废处理等功能。
尽管计算机可以处理这些功能,实际的操作仍需人为完成,如将书籍借出、摆放书架和进行报废等。
用例与概念模型
用例图表示信息的输入和引用,通常包含“登记”、“刷新”、“删除”、“维护”、“搜索”、“查询”等词语。
概念模型用来表示系统中应记录的信息,包括用户、图书、作者等实体及其关系。
概念模型组成 实例
用户 姓名、出生日期、性别、住址、电话号码
图书 图书编号、借阅明细
借阅 借阅日期、还书日期
实际工作的分配
计算机在业务应用程序中主要工作是记录和搜索信息,而实际的判断和交涉工作由人完成。
对于金钱交易,某些系统能够仅依靠计算机记录来处理,而不需要实际的现金。
嵌入式软件的特点
嵌入式软件定义
“嵌入式软件是‘嵌入到’机器中的控制程序。”

嵌入式软件广泛应用于家用电器(如空调、洗衣机)和高科技产品(如手机、汽车导航系统)。
它直接替代现实世界中的工作,例如,电饭煲实际做饭,洗衣机洗衣服等。
嵌入式软件的功能
嵌入式软件能够持续运行并无需人为干预,例如全自动洗衣机和电饭煲的操作。
这些系统依赖于传感器等设备来自律运行,进行自动控制。
特征 业务应用程序 嵌入式软件
主要功能 记录信息 驱动机器,替代人类工作
操作依赖 人工操作 自动执行,无需人工干预
工作性质 记录和搜索 持续运行,使用传感器自律工作
嵌入式软件的业务分析
业务分析的重要性
嵌入式软件的业务分析是对机器被发明之前的工作情形进行整理。
例如,洗衣机的发明前,人们在河边洗衣服,电饭煲的发明前,人们使用灶台做饭。
活动图的应用
在嵌入式软件中,可以使用活动图表示现实世界的工作情形。
状态机图与全自动工作
状态机图的使用
“状态机图用于表示全自动工作的情形。”

例如,空调的运转原理可以通过状态机图来表示,当温度超过或低于设定值时,空调会自动制冷或停止。
状态 动作
超过设定温度 制冷
低于设定温度 停止
设计目标与软件开发
可维护性与可重用性
当今软件设计更加重视可维护性和可重用性,而不仅仅是运行效率。
设计目标包括去除重复、提高构件独立性及避免依赖关系循环。
设计目标 说明
去除重复 避免功能重复,提高代码可读性与可维护性
提高构件独立性 增强子系统间的独立性,便于理解和修改
避免依赖关系循环 确保软件结构的稳定性与可重用性
内聚度与耦合度
内聚度:功能之间的紧密结合程度,越高越好。
耦合度:构件间相互依赖的程度,越低越好。
“内聚度高、耦合度低的设计意味着构件的功能密切相关,而相互之间的依赖较少。”

建模的乐趣
“建模技术不断发展,覆盖了整个软件开发的上游工程,能够使软件开发更具趣味性。”

通过建模,开发者能够更好地理解需求,编写出符合现实世界的逻辑软件。
这项工作充满挑战,但也充满乐趣。
🏗️ 超类与接口的设计
超类与子类
超类:在面向对象编程中,超类是被其他类所继承的类。
子类:子类是从超类派生出来的类,它继承超类的属性和方法。
接口与实现类
接口:定义了类必须实现的一组方法,不提供具体的实现。
实现类:实现接口定义的方法,具体提供功能。
依赖与关联
依赖:类与类之间的一种关系,表示一个类依赖于另一个类,通常通过参数或返回值传递。
关联:表示两个类之间的关系,通常是一个类包含对另一个类的引用。
UML 类图
图10-6展示了UML类图和包图中箭头表示的依赖关系的方向。

🌍 面向对象设计的“感觉”
“面向对象设计的感觉是拟人化和职责分配。”

设计目标
在设计易于维护和重用的软件时,需要考虑以下目标:

拟人化:将软件的职责与现实世界中的人或组织进行类比,以便更好地分配任务。
职责分配:将复杂功能的实现分配给不同的子系统或组件。
复杂性的处理
大规模软件的复杂性需要将职责分配给各个子系统,类似于现实世界中的组织结构。
在设计阶段,务必考虑到这种职责分配。
拟人化的表达
在评审设计时,常会听到诸如“该类知道这个信息,但不知道那个信息”的说法,体现了类的拟人化。

🏦 软件创建的奇妙世界
银行存款的取款处理:将软件进行职责分配的情形与现实世界进行类比,例如银行账户相当于钱包。
通过请求“账户”对象进行取款,相当于请求钱包“给我3万日元”。
角色的拟人化
在设计中,无生命的对象(object)承担责任,彼此发送消息以完成整体工作。
💻 设计阶段的思考
“面向对象设计的感觉是将现实世界的逻辑集合映射到软件结构中。”

OOP与现实世界的关系
在进行OOP(面向对象编程)设计时,尽管知道现实世界与软件结构不同,但仍会存在“它们是一样的”这种错觉。
定义软件专用对象
在应用程序设计中,除了与现实世界中存在的事物相应的对象之外,还会定义许多软件专用的对象来承担具体职责,最终实现整体功能。

📚 参考文献
敏捷软件开发:介绍了设计类时遵循的设计原则和模式等内容。
设计模式解析:结合GoF设计模式的应用示例,具体讲解职责分配等内容。
修改代码的艺术:通过编写测试代码改善设计的手法。
领域驱动设计入门:介绍将问题领域的知识反映到软件结构中的开发方法。
🔄 敏捷开发与迭代式开发流程
敏捷开发的特点
迭代式开发流程:通过阶段性开发和用户反馈,灵活应对变化。
XP(极限编程):强调沟通、反馈、简单和勇气的四个价值。
Scrum框架
角色:

产品负责人
开发团队
Scrum Master
迭代与冲刺:Scrum通过循环执行多次迭代(冲刺)来推进软件开发作业。

敏捷软件开发宣言
“个体和互动高于流程和工具;工作的软件高于详尽的文档;客户合作高于合同谈判;响应变化高于遵循计划。”

⚙️ 开发流程的类型
瀑布式开发流程
定义:依次实施需求定义、设计、编码和测试等作业。
问题:需求定义阶段可能存在不全面、意见不一致等问题。
迭代式开发流程
优点:不在一开始就确定所有需求规格,通过多次中间发布获取用户反馈,灵活应对变化。
🏆 结论
在面向对象设计和敏捷开发过程中,合理的职责分配和灵活的开发流程是实现可维护、可重用软件的关键。

🛠️ 敏捷开发实践
“敏捷开发是一种以轻量级迭代式开发方法为基础的软件开发方式,强调代码的质量和快速反馈。”

  1. 敏捷开发概述
    敏捷开发(Agile Development):以XP(极限编程)为代表的轻量级迭代式开发方法的总称。
    代码质量:在敏捷开发中,从工程的初始阶段就开始编写最终成果的代码,并在整个工程期间确保代码质量。
  2. 支持敏捷开发的实践
    在敏捷开发过程中,有三种具有代表性的实践方法,这些方法不仅适用于敏捷开发,也广泛应用于其他开发模式:

实践 内容
测试驱动开发(TDD) 先编写测试代码,然后编写主体代码。
重构(Refactoring) 在保持外部规格不变的情况下,安全地改善代码内部结构。
持续集成(CI) 定期自动执行编译、构建和单元测试,确保代码随时可以交付。
3. 测试驱动开发(TDD)
TDD 的作业步骤
编写测试代码:将要开发的代码的规格和期待的动作形成具体的形式。
编译通过:编写所需的最低限度的逻辑。
确认失败情况:测试代码应当在这一阶段失败。
编写代码:编写使测试成功的代码。
去除重复的代码:改善代码,保持其整洁性。
TDD 的主要优势在于能够快速发现和修复缺陷,使得设计和编码中的问题可以在几分钟内被识别。

  1. 重构
    重构的定义与步骤
    重构是指在不改变程序外部规格的前提下,安全地改善其内部结构。重构的步骤如下:

创建一个名称合适的新函数。
将待提炼的逻辑复制到新函数中。
修改局部变量为参数或返回值以适应新函数。
进行编译。
修改原函数以调用新函数。
编译并测试。
重构能够提高代码的可维护性和可重用性,确保在持续开发中代码的质量不会下降。

  1. 持续集成(CI)
    CI 的重要性
    持续集成是一种保持代码随时可以交付的状态的实践,主要通过以下方式实现:

CI 服务器:准备专用的机器环境,定期自动执行编译、构建和单元测试。
快速反馈:通过频繁的构建和测试,能够迅速发现和处理缺陷,提高团队的质量意识。
6. 敏捷开发与面向对象的关系
敏捷开发与面向对象(OOP)有着深刻的联系,虽然两者并无直接关系,但许多技术人员在推进敏捷开发时也在使用面向对象的技术。这种结合促进了开发效率的提升。

关系 描述
技术吻合 敏捷开发实践与面向对象的开发技术相辅相成。
人员联系 推进敏捷开发的人与面向对象的技术人员重叠较多。
7. 不存在最好的开发流程
“并不存在一种适用于所有情况的最佳开发流程。”在实际的软件开发中,应该参考不同的开发流程,选择适合具体工程的推进方法。

关键要点
灵活性:开发流程应根据项目需求和团队情况进行调整。
人际因素:团队协作和沟通在软件开发中至关重要,往往比开发流程本身更为重要。
8. 结论
随着技术的不断进步,新的开发流程和工具将不断涌现,但敏捷开发的基本原则和实践方法将继续在软件开发中发挥重要作用。面向对象技术的掌握将为开发人员提供更大的灵活性和效率。

💻 设计模式与面向对象编程
设计模式的使用
“设计模式是一种解决特定问题的可重用解决方案,但在不合适的场合使用可能会导致反效果。”

设计模式的应用注意事项
设计模式应当在合适的场合使用,否则可能导致系统难以理解和维护。
在设计和代码评审阶段,如果频繁听到“这好像不是面向对象的设计”的评论,需要重新审视设计的初衷。
软件开发的乐趣
“软件开发是一项需要动脑的有趣的工作,面向对象编程让这一过程更加愉悦。”

软件开发的乐趣来源
从零开始编写程序并立即看到运行结果是一种乐趣。
在团队中协作完成项目时的集体荣誉感也非常迷人。
面向对象编程(Object-Oriented Programming, OOP)通过类、多态和继承的使用,使得软件开发更加有趣。
面向对象技术的魅力
设计模式带来解谜的乐趣。
建模如作曲或绘画,具有创造性。
实践敏捷开发方法使团队更加活跃。
面向对象编程的学习
“很多人认为面向对象编程很难,但它实际上是让软件开发更轻松的工具。”

面向对象编程的特性
面向对象编程不仅方便,还能激发好奇心。
掌握面向对象技术后,软件开发将变得更加轻松。
推荐书籍
书名 作者 描述
《オブジェクト脳のつくり方——Java·UML·EJBをマスターするための究極の基礎講座》 牛尾刚 通过动手实践逐步培养对面向对象的感觉,包含有趣的演练。
《Head First Java(中文版)》 Kathy Sierra, Bert Bates 深入覆盖Java的基本结构与其他相关技术,适合学习面向对象编程。
函数式语言的基本结构
函数式语言与命令式语言的区别
纯函数式语言如Haskell不支持返回值为void的函数。
Haskell不使用return语句,所有函数返回的都是求值结果。
函数式语言的特征
特征 说明
使用函数编写程序 以函数为主要构件,不同于面向对象语言的类。
所有表达式返回值 函数和表达式都必须返回值,反映数学中的函数概念。
将函数作为值处理 函数可以存储在变量中,作为参数传递。
可以灵活组合函数和参数 通过部分应用和函数组合创造新函数。
没有副作用 函数不改变外部状态。
使用模式匹配和递归 处理循环逻辑。
编译器自动进行类型推断 提高编程便捷性。
重要概念
部分应用与柯里化
部分应用:针对拥有多个参数的函数,仅应用部分参数。
柯里化:将多个参数的函数转换为一系列单一参数的函数。
函数组合
将多个函数汇总创建新函数的过程,使用.符号表示。
高阶函数
“高阶函数是接收函数作为参数或返回值的函数。”

通过这些特性,函数式语言提供了灵活且强大的编程方式,使得构建复杂的程序变得更加简洁和高效。

📜 特征5:没有副作用
副作用的定义
“副作用”(side effect)在编程领域指的是“根据参数计算返回值之外的操作”,例如修改变量和外部输入/输出。

没有副作用的程序
没有副作用的程序 是指不修改变量,完全不执行画面、网络、数据库和文件等的外部输入/输出的程序。
纯函数式语言(如Haskell)中的变量一旦设置后就不能再修改,这类似于Java中的final变量和C/C++中的const变量。
绑定与变量
在函数式语言中,给变量设置值的操作称为绑定(binding),而不是替换(substitution)。
变量在此情况下并非指向存储的内存区域,而是指向值或表达式本身。
引用透明性
引用透明性(referential transparency)是没有副作用函数的一个重要特性。意为如果参数相同,无论调用多少次,返回值都相同。
没有副作用的益处
益处 解释
测试轻松 测试用例只需关注参数的各种情况,无需考虑函数引用的变量状态。
理解更容易 不再存在全局变量的问题,可以减少程序错误调查的复杂性。
提高构件的独立性 函数仅将参数转换为返回值,便于创建通用构件,有利于重用。
⏳ 延迟求值
延迟求值的定义
延迟求值(lazy evaluation)是指在程序运行时不是从头开始依次进行求值,而是在实际需要的时间点对各个表达式进行求值。
延迟求值的实现示例
以下是使用Java的示例代码(假设支持延迟求值):

getSalary 函数
java
Copy
/**

  • @param employee 员工
  • @param workHours 实际出勤时间
  • @return 实发工资
    */
    int getSalary(Employee employee, int workHours) {
    // 当员工为普通员工时,根据实际出勤时间计算加班费,加到固定工资上

    }
    调用 getSalary 函数
    java
    Copy
    getSalary(employee, getWorkHours(employee));
    执行方式
    执行方式 说明
    一般的执行方式 在getSalary执行前调用getWorkHours函数。
    延迟求值方式 仅在需要实际出勤时间时才调用getWorkHours。
    延迟求值的优势
    提高执行效率,避免不必要的计算。
    🔄 循环处理:模式匹配与递归
    使用模式匹配
    模式匹配(pattern matching)是根据参数的值来分情况定义函数的结构。
    示例代码:convertTab
    haskell
    Copy
    convertTab ‘\t’ = " "
    convertTab c = [c]
    convertTab 函数规格
    参数的值 处理
    ‘\t’ 将制表符转换为半角空格
    其他情况 将输入的字符直接转换为字符串型
    使用递归
    示例代码:计算阶乘的factorial函数
    haskell
    Copy
    factorial 1 = 1
    factorial n = n * factorial (n - 1)
    阶乘计算过程
    参数的值 处理
    1 返回1
    n 返回n × ((n-1) 的阶乘)
    通过模式匹配和递归,函数式语言能更简洁明了地编写循环处理。

🔍 类型推断
类型推断的定义
类型推断(type inference)是指编译器能够自动判断变量和函数的类型,而无需显式声明。
示例代码:increment函数
haskell
Copy
increment x = x + 1
类型推断过程
编译器根据“+ 1”的运算推断x为数值型。
多态的定义
多态(polymorphism)允许函数可以应用于非特定多种类型。
示例:Haskell的head函数类型为[a] -> a,可根据参数类型动态决定返回值类型。
📝 总结函数式语言的特征
特征 说明 相关术语
使用函数编写程序 函数应用
所有表达式都返回值 表达式、表达式求值、Lambda 表达式
将函数作为值处理 头等函数、高阶函数
灵活组合函数和参数 部分应用、柯里化、函数组合
没有副作用 副作用、绑定、引用透明性、延迟求值
使用模式匹配和递归 模式匹配、递归
类型推断 类型推断、多态、多态类型、类型变量
🖥️ 函数式语言概述
🌐 静态与动态类型
类型分类
静态类型语言:在程序编译时进行类型检查,例如 Haskell 和 Miranda。
动态类型语言:在程序运行时进行类型检查,例如 Scala、OCaml、F#、Common Lisp、Scheme、Erlang。
类型 检查时机 语言示例
静态类型 编译时 Haskell, Miranda
动态类型 运行时 Scala, OCaml, F#, Common Lisp, Scheme, Erlang
🔄 纯函数式与非纯函数式语言
纯函数式语言
基本上不允许副作用。
例子:Haskell。
非纯函数式语言
允许副作用,支持将值赋给变量的语法。
例子:Scala、OCaml、F#、Common Lisp、Scheme、Erlang。
💡 函数式语言的优势
简洁性:使用函数式语言编写程序的代码量可以减少到传统命令式语言的十分之一到二分之一,易于理解和维护。

可重用性:利用无副作用的函数,或将函数作为头等函数处理,可以编写出通用性强的构件。

并发处理:由于没有副作用,表达式的执行顺序不影响结果,适合并发处理,减少多线程共享内存区域的风险。

代码示例
使用 Monad 结构(例如在 Haskell 中)实现输入/输出:

haskell
Copy
– Haskell 中的Monad示例
main :: IO ()
main = do
putStrLn “Hello, World!”
📈 函数式语言的课题
运行时性能:函数式语言早期因硬件环境限制,性能未能充分实现,但在现代虚拟机环境(如 Java 和 .NET)上已经不再是大问题。

理解难度:函数与数据的区分模糊,类型不声明,使用模式匹配和递归等,给习惯传统语言的程序员带来挑战。

🧩 函数式语言与面向对象的关系
相似性:两者都旨在提高软件的可维护性和可重用性,但实现方法不同。

不同之处:

面向对象编程通过类来封装变量和过程,解决全局变量问题。
函数式语言禁止修改变量,通过参数和返回值传递信息。
面向对象与函数式对比
特性 面向对象编程 函数式编程
变量处理 类中封装 不可修改变量,使用参数传递
结构 类是基本构件 函数是基本构件
🔄 函数式编程掌握
当前主流语言(如 Java、Python、JavaScript、C# 和 Ruby)支持面向对象和函数式编程结构。
理解头等函数、Lambda 表达式和高阶函数等结构对熟练使用这些语言至关重要。
编写无副作用的函数或方法,有助于提高程序的维护性和重用性。
示例:Java 的函数式编程结构
Stream 接口:处理数据集合,支持头等函数和 Lambda 表达式。
java
Copy
// Java 中使用 Stream 的示例
List names = Arrays.asList(“Alice”, “Bob”, “Charlie”);
names.stream()
.filter(name -> name.startsWith(“A”))
.forEach(System.out::println);
📚 学习资源推荐
Haskell:学习函数式语言的结构和思想。
Scala:作为混合语言,结合了面向对象和函数式编程的特性。
Lisp:了解函数式语言的起源和基

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值