Skip to content

创建型模式

Abstract Factory(抽象工厂)

意图

提供一个接口以创建一系列相关或相互依赖的对象,而无需指定它们具体的类。

一般不会直接被实例化,通常作为其他派生类的基类使用。不同于接口,抽象类内部可以实现某些细节,(TS 中用 abstract 关键字定义)。 由于派生类都实现了相同的方法,而这些方法可能会有一些共通性,那么这个时候就可以将这些共通性单独的形成一个类。

AbstractFactory

声明一个创建抽象产品对象的操作接口:

javascript
// 比如要创建一个 widget,那么需要实现 createScrollBar,createWindow 两个方法
class WidgetFactory {
  createScrollBar() {
  	throw new Error('未实现createScrollBar方法')
  }
  createWindow() {
    throw new Error('未实现createWindow方法')
  }
}
// 比如要创建一个 widget,那么需要实现 createScrollBar,createWindow 两个方法
class WidgetFactory {
  createScrollBar() {
  	throw new Error('未实现createScrollBar方法')
  }
  createWindow() {
    throw new Error('未实现createWindow方法')
  }
}

ConcreteFactory

实现创建具体产品对象的操作

javascript
class GoogleWidgetFactory {
  createScrollBar() {
    return new GoogleScrollBar()
  }
  createWindow() {
    ...
  }
}

class BaiduWidgetFactory {
  createScrollBar() {
    return new BaiduScrollBar()
  }
  createWindow() {
    ...
  }
}
class GoogleWidgetFactory {
  createScrollBar() {
    return new GoogleScrollBar()
  }
  createWindow() {
    ...
  }
}

class BaiduWidgetFactory {
  createScrollBar() {
    return new BaiduScrollBar()
  }
  createWindow() {
    ...
  }
}

AbstractProduct

为一类产品对象声明一个接口

javascript
class ScrollBar {
  // 定义一些内容
}

class Window { // todo }
class ScrollBar {
  // 定义一些内容
}

class Window { // todo }

ConcreteProduct

定义一个将被相应的具体工厂创建的产品对象,需实现AbstractProduct接口

javascript
class GoogleScrollBar extends ScrollBar {
  // 实现一些 scrollbar 相关的内容
}
class BaiduScrollBar extends ScrollBar {
  // 实现一些 scrollbar 相关的内容
}
class GoogleScrollBar extends ScrollBar {
  // 实现一些 scrollbar 相关的内容
}
class BaiduScrollBar extends ScrollBar {
  // 实现一些 scrollbar 相关的内容
}

理解

一个复杂的对象创建的时候需要依赖几个简单的对象,比如迷宫,依赖于 门,房间,墙壁,并且他们有以下关系:

  • 不同的门,房间,墙壁能构建出不同的迷宫,比如迷宫 A,迷宫 B。
  • 门,房间,墙壁有相应的关系。

迷宫:

  • 由一个工厂(具体的工厂类)来创建,这个工厂需要能有相应的 门,房间,逻辑放在抽象工厂类中实现。

门,房间,墙壁:

  • 同样需要实现一个抽象类,具体的产品(零件)实现细节。
ts
// 抽象工厂
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
}
// 抽象工厂
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对象的各个部件指定抽象接口

javascript
// 迷宫创建
class MazeBuilder {
  buildRoom() {
    throw new Error('buildRoom 方法未实现')
  }
  buildDoor() {
    throw new Error('buildDoor 方法未实现')
  }
}
// 迷宫创建
class MazeBuilder {
  buildRoom() {
    throw new Error('buildRoom 方法未实现')
  }
  buildDoor() {
    throw new Error('buildDoor 方法未实现')
  }
}

ConcreteBuilder

实现Builder接口以构造和装配该产品的各个部件

javascript
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
  }
}
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接口的对象

javascript
class MazeGame {
  createComplexMaze(builder) {
    builder.buildRoom()
    builder.buildDoor()
    builder.buildRoom()
  }
}
class MazeGame {
  createComplexMaze(builder) {
    builder.buildRoom()
    builder.buildDoor()
    builder.buildRoom()
  }
}

Product

表示被构造的复杂对象

javascript
const mazeGame = new MazeGame()
const builder = new StandardBuilder()
mazeGame.createComplexMaze(builder)
builder.getMaze()

const countBuilder = new CountBuilder()
mazeGame.createComplexMaze(countBuilder)
countBuilder.getCount()
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

定义工厂方法所创建的对象的接口

javascript
class Document {
  open() { }
  close() { }
  save() { }
}
class Document {
  open() { }
  close() { }
  save() { }
}

ConcreteProduct

实现Product接口

javascript
class MyDocument extends Document {
  open() { 
    // todo 详细内容实现
  }
  close() { }
  save() { }
}
class MyDocument extends Document {
  open() { 
    // todo 详细内容实现
  }
  close() { }
  save() { }
}

Creator

声明工厂方法,返回一个Product类型的对象。

javascript
class Application {
  createDocument() { 
  	// 返回 Product 对象
  }
  newDocument() { }
  openDocument() { }
}
class Application {
  createDocument() { 
  	// 返回 Product 对象
  }
  newDocument() { }
  openDocument() { }
}

ConcreteCreator

重定义工厂方法以返回一个ConcreteProduct对象

javascript
class MyApplication extends Application {
  createDocument() {
    return new MyDocument()
  }
}
class MyApplication extends Application {
  createDocument() {
    return new MyDocument()
  }
}

Prototype(原型)

意图

用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。

最典型的例子:js中的原型

javascript
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')
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(单例)

意图

保证一个类仅有一个实例,并提供一个访问它的全局访问点。

饿汉式:在类加载的时候就已经创建好实例了。

javascript
class IDGenerator {
  id = 0
  static instance = new IDGenerator();
  static getInstance() {
    return IDGenerator.instance
  }
  getId() {
    return ++this.id
  }
}
class IDGenerator {
  id = 0
  static instance = new IDGenerator();
  static getInstance() {
    return IDGenerator.instance
  }
  getId() {
    return ++this.id
  }
}

懒汉式:支持延迟加载。

javascript
class IDGenerator {
  id = 0
  static instance = null
  static getInstance() {
    if (!IDGenerator.instance) {
      IDGenerator.instance = new IDGenerator()
    }
    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
  }
}

总结

  • 抽象工厂侧重于定义统一接口,然后派生类去补全这些接口。
  • 生成器侧重于创建一个复杂对象,定义不同的生成器创建不同的对象