设计模式:类和对象及面向对象
面向对象
面向对象程序设计(Object-Oriented Programming, OOP)是一种范式,基本理念是将数据块与数据相关的行为封装成特殊的、名为对象的实体,同时对象实体的生成工作则是由程序员给出的一系列“蓝图”,这些蓝图就是“类”。
类
类(Class)是面向对象程序设计(OOP,Object-Oriented Programming)实现信息封装的基础。类是一种用户定义的引用数据类型,也称类类型。每个类包含数据说明和一组操作数据或传递消息的函数。类的实例称为对象。
这里有一个 Cat
类,我们用 UML 类图来表示一下。

这是一个 Cat
, 包含了成员变量(状态)、方法(行为),+
代表共用方法,同样可以用 -
代表私有方法。类 Cat
就是对猫这一动物的抽象 用代码来描述就是:
class Cat {
constructor(name, gender, age, weight, color) {
this.name = name
this.gender = gender
this.weight = weight
// ...
}
breath() {}
eat(food: Food){}
run(desitination: number){}
// ...
}
对象
如果说类是定义对象结构的蓝图,那么对象就是类的具体实例。
比如,你拥有一只叫做 penpen
的猫,也可以拥有一只叫做 lulu
的猫:
这两只猫是不同的猫,区别在于拥有不同的属性。
用代码描述就是:
const penpen = new Cat("penpen", "male", 7 , /*省略...*/)
const lulu = new Cat("lulu", "female", 5, /*省略...*/)
INFO
JavaScript 是一门多范式的编程语言,ES6 之后又提供了 class
语法糖。这么看来 JavaScript 也是一门面向对象的编程语言
面向对象设计基础
面向对象程序设计的四个基本概念使其区别于其他的编程范式。
抽象
抽象是一种反映真实世界对象或现象中特定内容的模型, 它能高精度地反映所有与特定内容相关的详细信息, 同时忽略其他内容。
例如,飞机模拟器和航班预订中都会包含一个 Airplane
类,但两者对飞机的具体抽象是不同的,前者包括了飞机飞行相关的信息,后者只需要关心座位图,以及座位是否可被预订即可:
// 飞行模拟器
class Airplane {
speed: number
altitude: number
rollAngle: number
pitchAngle: number
yawAngle: number
fly() {}
}
// 航班预订
class Airplane {
seats: number
reserveSeat(n) {}
}
封装
封装是指一个对象对其他对象隐藏其部分状态和行为,而仅向程序其他部分暴露有限的接口的能力。
比如想要启动一辆车,我们只需要转动钥匙即可启动,无需打开引擎,手动界限,转动曲轴等一些列操作。这些操作细节都被隐藏在了汽车内部,你所看到的只有一些简单的接口:开关,方向盘,刹车等。
大部分编程语言的接口和抽象类都基于抽象和封装的概念。 比如通过接口(interface) 去规范及定义对象之间的交互协议:
// 多个类实现同一个接口
interface Transport {
move(origin: number, destination: number, passengers: number): void
}
class Airplane implements Transport {
move(origin: number, destination: number, passengers: number): void {}
}
class Bus implements Transport {
move(origin: number, destination: number, passengers: number): void {}
}
class Taxi implements Transport {
move(origin: number, destination: number, passengers: number): void {}
}
继承
继承是指根据已有类创建新类的能力。继承最主要的好处是复用代码。
继承最大的好处就是避免重复编写大量相同的代码。只需要扩展已有类,并把新的功能放到子类中。使用继承后,子类将拥有和父类相同的接口。 在大多数编程语言中,子类仅能继承自一个父类,但是可以实现多个接口:
interface Legged {
run(destination: number):void
}
interface Breather {
breathe(): void
}
class Animal implements Legged, Breather {
name: string
age: number
constructor(name:string, age: number) {
this.name = name
this.age =age
}
breathe(): void {
throw new Error('Method not implemented.')
}
run(destination: number): void {
throw new Error('Method not implemented.')
}
}
class Cat extends Animal {
meow() {
console.log('meow meow...')
}
}
const cat = new Cat('no.88', 3)
console.log(cat.name)
console.log(cat.age)
cat.breathe()
cat.meow()
多态
多态是指程序能够检测对象所属的实际类,并在当前上下文不知道其真实类型情况下调用其实现的能力。
多态其实就是我们平时开发中经常见到的 duck typing
的概念:
class Animal {
makeSound() {}
}
class Cat extends Animal {
makeSound() {
console.log('meow meow..')
}
}
class Dog extends Animal {
makeSound() {
console.log('bark bark...')
}
}
const animals = [new Cat(), new Dog()]
animals.forEach(animal => animal.makeSound())
// meow meow...
// bark bark...
对象之间的其他关系
除了上面有提到过的继承、实现之外,对象之间还存在着一下几种关系
依赖
修改A类的定义造成B类的变化,这两个类之间就存在依赖关系。
class Course {
learnMathmatic() {
console.log('learn mathmatic')
}
}
class Studen {
getKnownledge() {
new Course().learnMathmatic()
}
}
如果一不小心修改了 Course 中的 learnMathmatic 方法(实现逻辑/方法签名)的话,学生获取的可能就不是数学知识了,这就是依赖关系。
关联
关联是一个对象使用另一个对象或与另一个对象进行交互的关系
class Student {
remember(knownledge: any) {}
}
class Course {
getKnownledge(){}
}
class Professor {
student!: Student
teach(c: Course) {
this.student.remember(c.getKnownledge())
}
}
上面的例子中,Professor 教授与 Student 类就产生了关联关系,但是 Student 和 Course 是依赖关系。关联是一种特殊的依赖。从代码形式上来看,依赖更像是构造函数的调用,A 类的构造函数依赖 B 类构造函数的实例。而关联更像是 A 的的成员变量是 B 类的实例。
聚合
聚合是一种特殊类型的关联,用于表示多个对象之间“一对多”、“多对多”或“整体对部分”的关系。
聚合更是一种强耦合的关联关系。关联和聚合的代码表现形式比较类似,仅仅是语义上有些差别:关联关系中类都是相互独立的,但是聚合关系中更像是包容关系,即 A 类 包容 B 类:
class KeyBoard {}
class Mouse {}
class Computer {
keyboard!: KeyBoard
mouse!: Mouse
}
Computer 类中包含了 KeyBoard 类和 Mouse 类,即整体与个体的区别,其中 Computer 和 KeyBoard 是可以分离的,各自都具有独立的生命周期,KeyBoard 可以分属于多个 Computer 类,也可以被多个对象共享。
组合
组合是一种特殊类型的聚合,其中一个对象由多个其他对象的实例构成。
组合是比聚合耦合度更强的一种关联关系。组合和聚合在代码层面上也没有什么区别,更多是在语义话上的区别。组合于聚合同样都是 整体-部分的关系,但聚合和组合的唯一区别就是,对于组合来说个体脱离了整体是无法单独存在的。
class Brain{}
class Person {
brain!: Brain
}
其中 Brain(大脑)被包含于 Person 中,但是两者有共同的生命周期,Person 死掉的话,大脑同样会死掉,且大脑无法脱离 Person 单独生存。
总结
简单了解了一下类与对象之间的关系后,就可以很方便的进行设计模式的学习了。