面向对象是如何工作的(How Objects Work)
How Objects Work - 面向对象是如何工作的
面向对象的全貌和概念
面向对象是从编程语言进化为编程技术的
1967 年挪威设计的 Simula 67 编程语言首次提出
艾伦 凯设计的 Smalltalk 沿用此架构,开创“面向对象”的概念
* The best way to predict future is to invent it - Alan Kay
面向对象三大混乱之源
术语洪流
比喻乱用
“一切都是对象”综合征
面向对象三大要素
类(封装)Encapsulation | class -> instance
多态 Polymorphism
继承 Inheritance
集合论和职责分配
集合论:在 OOP 中,类用于汇总子程序和变量。实例是基于类定义在运行时分配的内存区域
消息传递:在 OOP 中,消息传递是一种通过指定实例来调用类中汇总的子程序(方法)的结构
编程技术
OOP的出现的必然性之语言历史 - 计算机只可以解释用二进制编写的机器语言
机器语言
汇编语言:An assembly language is a low-level programming language designed for a specific type of processor
高级语言:
重视易懂性的结构化编程
荷兰科技加戴克斯特拉(Dijkstar):为了编写能够正确运行的程序,采用简单易懂的结构是非常重要的
1. 循序->顺序执行->从头开始顺序执行程序中编写的命令 2. 选择->执行某些判断,根据判断的结果决定接下来要执行的命令 3. 重复(循环)-> 在规定次数或某个条件成立期间,重复执行指定的命令群
提高子程序的独立性,强化可维护性
多个子程序之间共享的变量叫全局变量
减少全局变量对提高程序整体可维护性而言非常重要
避免全局变量引用造成的混乱,创造
1. 局部变量:只可以在子程序中使用的变量,在进入子程序时创建,退出子程序时消失 2. 按值传递(Call By Value):通过参数向子程序传递消息时,不直接使用调用端引用的变量,而是复制值以进行传递。
结构化语言的缺陷
全局变量问题:在子程序运行结束后依然需要保持的信息只能存放在子程序外面,即被保存为全局变量
可重用性差
OOP(Object Oriented Programming) - 编程架构
OOP 的出现解决结构化编程两个主要问题:
1. OOP 具有不使用全局变量的结构 2. OOP 具有除公用子程序之外的可重新结构
OOP 的类(Class)结构将紧密关联的子程序(函数)和全局变量汇总在一起,创建大粒度的软件构件
多态和继承能够将公用子程序无法很好地处理重复代码进行整合
Class 类的功能是汇总、隐藏和“创建很多个”
1. 汇总子程序和变量 -> 构件的数量会减少、函数的命名变的轻松、函数容易查找 2. 隐藏只在类内部使用的变量和子程序 -> 能对其他类隐藏类中的定义的变量和方法 3. 从一个类“创建很多个”实例 -> 指定实例,调用方法 * 实例是指类定义的实例变量所持有的内存区域
实例变量时存在期间长的局部变量或限定访问范围的全局变量
1. 能够隐藏,让其他类方法无法访问 2. 实例在被创建后一直保存在内存中,直至不再需要
Ploymorphis 多态创建“公用主程序”的结构
1. 多态是统一调用子程序端的逻辑的结构,即创建公用主程序的结构 2. 统一调用端的逻辑
Inherited 继承去除类的重复定义的继承
1. 继承就是"将类的共同部分汇总到其他类中的结构” 2. 继承是将类定义的共同部分汇总到另一个类文件中,并除去重复代码的结构
类型检查
1. 通过嵌入类型使工作变的轻松,指定的类型的原因: 1. 告诉编译器内存空间的大小 2. 防止程序发生错误 2. OOP 中将类当作类型使用 1. 将变量的类型指为类、将方法的参数类型指为类、将方法的返回值类型指定为类 2. 类型检查分为强类型和弱类型 -> 强类型:在编译时进行检查 / 弱类型:在运行时进行检查
OOP 进化
1. 包 -> Package 1. 用户创建层次结构 / 2. 用于防止类重命名 2. 异常 -> Exception 3. 垃圾回收 -> Grabage Collection GC
程序的内存结构
程序的内存区域分为 静态区、堆区、栈区
1. 静态区:从程序开始运行时产生,在程序结束前一直存在。所谓"静态"该区域中存储的信息配置在程序运行时不会发生变化 2. 堆区(heap): 程序运行时分配的内存储区域,程序开始运行时预先分配的大量内存区域,供多个线程使用 3. 栈区(Stack):由线程控制的内存区域。仅每个线程自身使用. * 各个线程依次调用子程序(OOP中的方法)。即子程序的内存区域,存储子程序的参数、局部变量和返回位置等信息 * LIFO(Last In First Out)
每个类只加载一个类信息
1. 当使用 OOP 编写的程序运行时,会从类创建实例进行动作。实际上,当程序运行时,在创建实例之前,需要将对应的类信息加载到内存中 * 类信息,是不依赖于各个实例的类固有信息 2. 每个类只加载一个方法中编写的代码信息 3. 加载信息的时间点: 1. 预先整体加载所有类信息 2. 需要时依次将类信息加载到内存中
每次创建实例都会使用堆区(Heap)
1. 执行创建实例的命令,程序会在堆区分配所需的大小内存,用于存储该类的实例变量 2. OOP 中的内存使用方法最大特征就是实例的创建方法 3. 使用 OOP 编写的程序大量使用有限的堆区来运行 4. 传统编程语言编写中,将代码和全局变量配置在静态区,并使用栈区传递子程序的调用信息
在变量中存储实例的指针
1. 指针表示内存区域中的位置的信息 2. 存储实例的变量存储的并不是实例的本身,而是实例的指针 3. 复制存储实例的变量需要多
应用技术
软件建模
业务分析:直接把我现实世界的情形
需求定义:考虑计算机的性质,确定计算机承担的工作范围
* 计算机擅长固定工作和记忆工作
设计:考虑硬件性能、操作系统和中间件的特性以及编程语言的表现能力等,确定软件结构
软件建模示例
活动图表示工作流程
用例图表示业务
概念模型表示系统信息
面对对象的设计的目标(可维护与可重用)
去除重复 (多态、继承)
提高构件的独立性 (高内聚、低耦合)
1. 内聚度:评判软件构件所提供功能互相结合紧密程度的标准,结合越紧密,内聚度越高,设计就越好 2. 耦合度:多个软件构件之间互相依赖的标准,依赖程度越低,耦合程度越低,设计越好
避免依赖关系发生循环
面向对象的设计“感觉”拟人化和职责分配
关联 -> 依赖 -> 继承(三角)-> 实现(三角)
函数式语言特征
使用函数来编写程序 - 函数应用
所有的表达式都有返回值 - 命令式语言、表达式、表达式求值、lambda 表达式
将函数作为值进行处理 - 头等函数、高阶函数
可以灵活组合函数和参数 - 部分应用、柯里化、函数组合
没有副作用 - 副作用、绑定、引用透明性、延迟求值
使用分类和递归编写循环处理 - 模式匹配、递归
编译器自动进行类型推断 - 类型推断、多态、多态类型、类型变量