创建型模式
Abstract Factory(抽象工厂)
意图
提供一个接口以创建一系列相关或相互依赖的对象,而无需指定它们具体的类。
一般不会直接被实例化,通常作为其他派生类的基类使用。不同于接口,抽象类内部可以实现某些细节,(TS 中用 abstract 关键字定义)。 由于派生类都实现了相同的方法,而这些方法可能会有一些共通性,那么这个时候就可以将这些共通性单独的形成一个类。
AbstractFactory
声明一个创建抽象产品对象的操作接口:
// 比如要创建一个 widget,那么需要实现 createScrollBar,createWindow 两个方法
class WidgetFactory {
createScrollBar() {
throw new Error('未实现createScrollBar方法')
}
createWindow() {
throw new Error('未实现createWindow方法')
}
}
ConcreteFactory
实现创建具体产品对象的操作
class GoogleWidgetFactory {
createScrollBar() {
return new GoogleScrollBar()
}
createWindow() {
...
}
}
class BaiduWidgetFactory {
createScrollBar() {
return new BaiduScrollBar()
}
createWindow() {
...
}
}
AbstractProduct
为一类产品对象声明一个接口
class ScrollBar {
// 定义一些内容
}
class Window { // todo }
ConcreteProduct
定义一个将被相应的具体工厂创建的产品对象,需实现AbstractProduct
接口
class GoogleScrollBar extends ScrollBar {
// 实现一些 scrollbar 相关的内容
}
class BaiduScrollBar extends ScrollBar {
// 实现一些 scrollbar 相关的内容
}
理解
一个复杂的对象创建的时候需要依赖几个简单的对象,比如迷宫,依赖于 门,房间,墙壁,并且他们有以下关系:
- 不同的门,房间,墙壁能构建出不同的迷宫,比如迷宫 A,迷宫 B。
- 门,房间,墙壁有相应的关系。
迷宫:
- 由一个工厂(具体的工厂类)来创建,这个工厂需要能有相应的 门,房间,逻辑放在抽象工厂类中实现。
门,房间,墙壁:
- 同样需要实现一个抽象类,具体的产品(零件)实现细节。
// 抽象工厂
abstract class Maze {
constructor() {
const door = this.createDoor()
const room = this.createRoom()
// 逻辑实现,绑定关系
room.leftDoor = door
console.log('door.width', door.width)
}
createDoor: () => void
createRoom: () => void
}
// 具体的工厂
class AMaze extends Maze {
// 创建具体的零件
createDoor() {
return new ADoor()
}
createRoom() {
return new ARoom()
}
}
class BMaze extends Maze {
// 创建具体的零件
createDoor() {
return new BDoor()
}
createRoom() {
return new BRoom()
}
}
// 抽象产品
abstract class Door {
width: number
height: number
}
// 具体的零件产品
class ADoor extends Door {
width: 10
height: 10
}
class BDoor extends Door {
width: 10
height: 10
}
参考
Builder(生成器)
意图
将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
当构建一个复杂的对象,需要经历若干步骤或选择,那么可以将这些步骤提取出来形成一个类叫做builder。这个类有点像抽象类,其派生类需要实现对应的方法(也就是定制的步骤、选择等)。那么创建复杂对象的时候只需要传入builder,然后调用定义好的方法即可。而具体的定制内容都放到派生类里去实现了。
Builder
为创建一个Product
对象的各个部件指定抽象接口
// 迷宫创建
class MazeBuilder {
buildRoom() {
throw new Error('buildRoom 方法未实现')
}
buildDoor() {
throw new Error('buildDoor 方法未实现')
}
}
ConcreteBuilder
实现Builder
接口以构造和装配该产品的各个部件
class StandardBuilder extends MazeBuilder {
buildRoom() {
console.log('standard room')
}
buildDoor() {
console.log('standard door')
}
getMaze() {
return 'maze'
}
}
class CountBuilder extends MazeBuilder {
buildRoom() {
console.log('room count 加1')
}
buildDoor() {
console.log('door count 加1')
}
getCount() {
return 0
}
}
Director
构造一个使用Builder
接口的对象
class MazeGame {
createComplexMaze(builder) {
builder.buildRoom()
builder.buildDoor()
builder.buildRoom()
}
}
Product
表示被构造的复杂对象
const mazeGame = new MazeGame()
const builder = new StandardBuilder()
mazeGame.createComplexMaze(builder)
builder.getMaze()
const countBuilder = new CountBuilder()
mazeGame.createComplexMaze(countBuilder)
countBuilder.getCount()
Factory Method(工厂方法)
意图
定义一个用于创建对象的接口,让子类决定实例化哪一类。
Product
定义工厂方法所创建的对象的接口
class Document {
open() { }
close() { }
save() { }
}
ConcreteProduct
实现Product
接口
class MyDocument extends Document {
open() {
// todo 详细内容实现
}
close() { }
save() { }
}
Creator
声明工厂方法,返回一个Product
类型的对象。
class Application {
createDocument() {
// 返回 Product 对象
}
newDocument() { }
openDocument() { }
}
ConcreteCreator
重定义工厂方法以返回一个ConcreteProduct
对象
class MyApplication extends Application {
createDocument() {
return new MyDocument()
}
}
Prototype(原型)
意图
用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。
最典型的例子:js中的原型
function User(name) {
this.name = name
}
User.prototype.say = (word) => {
console.log(word)
}
const userA = new User('A')
userA.say('I am A')
const userB = new User('B')
userA.say('I am B')
Singleton(单例)
意图
保证一个类仅有一个实例,并提供一个访问它的全局访问点。
饿汉式:在类加载的时候就已经创建好实例了。
class IDGenerator {
id = 0
static instance = new IDGenerator();
static getInstance() {
return IDGenerator.instance
}
getId() {
return ++this.id
}
}
懒汉式:支持延迟加载。
class IDGenerator {
id = 0
static instance = null
static getInstance() {
if (!IDGenerator.instance) {
IDGenerator.instance = new IDGenerator()
}
return IDGenerator.instance
}
getId() {
return ++this.id
}
}
总结
- 抽象工厂侧重于定义统一接口,然后派生类去补全这些接口。
- 生成器侧重于创建一个复杂对象,定义不同的生成器创建不同的对象