粥里有勺糖

vuePress-theme-reco 粥里有勺糖    2018 - 2023
粥里有勺糖 粥里有勺糖

Choose mode

  • dark
  • auto
  • light
关于我
备战春秋
  • 心得总结
  • 校招考点汇总
  • 面经汇总
  • 复习自查
技术笔记
  • 技术教程
  • 模板工程
  • 源码学习
  • 技术概念
  • 个人作品
  • 学习笔记
计算机基础
  • 算法与数据结构
  • 操作系统
  • 计算机网络
  • 设计模式
  • 剑指offer
大前端
  • javascript
  • vue
  • html
  • css
  • 🌏浏览器专题
  • Web性能优化
  • regexp
  • node
面试
  • 问解
  • javascript
  • css
  • 手撕代码
  • 性能优化
  • 综合问题
  • 面经汇总
  • 小程序
手撕代码
  • 数据结构与算法
  • javascript
  • css
个人站点
  • GitHub (opens new window)
  • 博客园 (opens new window)
  • 掘金 (opens new window)
线上作品
  • 轻取(文件收集) (opens new window)
  • 个人图床 (opens new window)
  • 考勤小程序 (opens new window)
  • 时光恋人 (opens new window)
  • 在线简历生成 (opens new window)
留言板
Github (opens new window)
author-avatar

粥里有勺糖

285

文章

40

标签

关于我
备战春秋
  • 心得总结
  • 校招考点汇总
  • 面经汇总
  • 复习自查
技术笔记
  • 技术教程
  • 模板工程
  • 源码学习
  • 技术概念
  • 个人作品
  • 学习笔记
计算机基础
  • 算法与数据结构
  • 操作系统
  • 计算机网络
  • 设计模式
  • 剑指offer
大前端
  • javascript
  • vue
  • html
  • css
  • 🌏浏览器专题
  • Web性能优化
  • regexp
  • node
面试
  • 问解
  • javascript
  • css
  • 手撕代码
  • 性能优化
  • 综合问题
  • 面经汇总
  • 小程序
手撕代码
  • 数据结构与算法
  • javascript
  • css
个人站点
  • GitHub (opens new window)
  • 博客园 (opens new window)
  • 掘金 (opens new window)
线上作品
  • 轻取(文件收集) (opens new window)
  • 个人图床 (opens new window)
  • 考勤小程序 (opens new window)
  • 时光恋人 (opens new window)
  • 在线简历生成 (opens new window)
留言板
Github (opens new window)
  • note

    • 学习笔记
    • Chrome 调试技巧-基础
    • Chrome 调试技巧-Console
    • Chrome 调试技巧-Network
    • Chrome 调试技巧-Elements
    • Chrome 调试技巧-Drawer
    • Chrome 调试技巧-workspace
    • 设计模式-设计原则
    • 设计模式-创建型模式
    • 设计模式-结构型模式
    • 学习笔记:TypeScript装饰器

设计模式-创建型模式

vuePress-theme-reco 粥里有勺糖    2018 - 2023

设计模式-创建型模式

粥里有勺糖 2021-05-18 技术笔记学习笔记

# 设计模式-创建型模式

# 工厂模式

# 概念

  • 将创建对象的过程单独封装
  • 简单来说,就是你需要什么东西不直接使用new的方法生成实例,然后统一通过工厂进行生产加工再生成实例

# 示例1

# 需求

一个简单的成员管理系统,成员有姓名,成员类型,职责等基础属性,设一个生成各种角色实例的方法

# 实现

function User(name, age, type, works) {
    this.name = name
    this.age = age
    this.type = type
    this.works = works
}

function userFactory(name, age, type) {
    const worksObj = {
        'teacher': ['传道', '授业', '解惑'],
        'student': ['上课', '写作', '课外实践'],
        // ... any more
    }
    return new User(name, age, type, worksObj[type] || [])
}
const s1 = userFactory('小明',18,'student')
const t1 = userFactory('王刚',28,'teacher')
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

# 示例2

# 需求

图形库中有各各样的形状,如三角形,圆形,矩形等等,设计一个获取图形的方法

# 实现

function Circle(){
    this.name = 'circle'
    this.r = 0
}

function Triangle(){
    this.name = 'triangle'
    this.a = 0
    this.b = 0
    this.c = 0
}

function Rectangle(){
    this.name = 'rectangle'
    this.width = 0
    this.height = 0
}

function shapeFactory(shape){
    switch(shape){
        case 'circle':return new Circle()
        case 'triangle':return new Triangle()
        case 'rectangle':return new Rectangle()
        default: return null;
    }
}

const c1 = shapeFactory('circle')
const t1 = shapeFactory('triangle')
const r1 = shapeFactory('rectangle')
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

# 抽象工厂模式

# 概念

  • 围绕一个超级工厂创建其他工厂

# 示例1

# 需求

通常一个系统中除了成员管理,还包含日志管理等,不同系统中这些实例对象的属性可能不一致,但系统中都存在此类管理功能的需求,将系统的行为进行抽象。

# 实现

class AbstractSystemFactory {
    userFactory() {
        throw new Error('不允许直接调用抽象工厂方法')
    }

    logFactory() {
        throw new Error('不允许直接调用抽象工厂方法')
    }
}

class TradingSystem extends AbstractSystemFactory {
    userFactory() {
        return new TradingSystemUserFactory()
    }

    logFactory() {
        // 类似实现
    }
}

class AbstractSystemUserFactory {
    createUser() {
        throw new Error('不允许直接调用抽象工厂方法')
    }
}

class TradingSystemUserFactory extends AbstractSystemUserFactory {
    createUser(name, age) {
        return new TradingSystemUser(name, age)
    }
}

class TradingSystemUser {
    constructor(name, age) {
        this.name = name
        this.age = age
    }
    printInfo() {
        console.log(this.name, this.age);
    }
}

const tradingSystem = new TradingSystem()
const tradingSystemUserFactory = tradingSystem.userFactory()

const tsu1 = tradingSystemUserFactory.createUser('xm',18)
tsu1.printInfo()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47

# 单例模式

# 概念

  • 一个实例只生产一次

# 多种实现方式

使用ES5(Function)与ES6(Class)实现

# 方式1

利用instanceof判断是否使用new关键字调用函数进行对象的实例化

function User() {
    if (!(this instanceof User)) {
        return
    }
    if (!User._instance) {
        this.name = '无名'
        User._instance = this
    }
    return User._instance
}

const u1 = new User()
const u2 = new User()

console.log(u1===u2);// true
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# 方式2

在函数上直接添加方法属性调用生成实例

function User(){
    this.name = '无名'
}
User.getInstance = function(){
    if(!User._instance){
        User._instance = new User()
    }
    return User._instance
}

const u1 = User.getInstance()
const u2 = User.getInstance()

console.log(u1===u2);
1
2
3
4
5
6
7
8
9
10
11
12
13
14

# 方式3

使用闭包,改进方式2

function User() {
    this.name = '无名'
}
User.getInstance = (function () {
    var instance
    return function () {
        if (!instance) {
            instance = new User()
        }
        return instance
    }
})()

const u1 = User.getInstance()
const u2 = User.getInstance()

console.log(u1 === u2);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

# 方式4

使用包装对象结合闭包的形式实现

const User = (function () {
    function _user() {
        this.name = 'xm'
    }
    return function () {
        if (!_user.instance) {
            _user.instance = new _user()
        }
        return _user.instance
    }
})()

const u1 = new User()
const u2 = new User()

console.log(u1 === u2); // true
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

当然这里可以将闭包部分的代码单独封装为一个函数

在频繁使用到单例的情况下,推荐使用类似此方法的方案

function SingleWrapper(cons) {
    // 排出非函数与箭头函数
    if (!(cons instanceof Function) || !cons.prototype) {
        throw new Error('不是合法的构造函数')
    }
    var instance
    return function () {
        if (!instance) {
            instance = new cons()
        }
        return instance
    }
}

function User(){
    this.name = 'xm'
}
const SingleUser = SingleWrapper(User)
const u1 = new SingleUser()
const u2 = new SingleUser()
console.log(u1 === u2);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

# 方式5

在构造函数中利用new.target判断是否使用new关键字

class User{
    constructor(){
        if(new.target !== User){
            return
        }
        if(!User._instance){
            this.name = 'xm'
            User._instance = this
        }
        return User._instance
    }
}

const u1 = new User()
const u2 = new User()
console.log(u1 === u2);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

# 方式6

使用static静态方法

class User {
    constructor() {
        this.name = 'xm'
    }
    static getInstance() {
        if (!User._instance) {
            User._instance = new User()
        }
        return User._instance
    }
}


const u1 = User.getInstance()
const u2 = User.getInstance()

console.log(u1 === u2);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

# 建造者模式

# 概念

  • 让简单的对象通过组合的方式构造成多种复杂对象
  • 一种创建复杂对象的最佳实践

# 示例

以团购火锅卷为例,通常有多种套餐类型可供选择,不同套餐由饮料,小吃,荤菜,素菜等等构成。饮料用瓶装,小吃用木碗装等等。

// 木盘子
class WoodenBowl {
    pack() {
        return 'WoodenBowl'
    }
}

// 瓶子
class Bottle {
    pack() {
        return 'Bottle'
    }
}

// 小吃用木碗装
class Snack {
    packing() {
        return new WoodenBowl()
    }
}

// 饮品用瓶装
class Drink {
    packing() {
        return new Bottle()
    }
}

// 可乐
class Coke extends Drink {
    price() {
        return 3.00
    }
    name() {
        return 'Coke'
    }
}

// 茶
class Tea extends Drink {
    price() {
        return 5.00
    }
    name() {
        return 'Tea'
    }
}

// 薯条
class FrenchFries extends Snack {
    price() {
        return 15.00
    }
    name() {
        return 'FrenchFries'
    }
}

// 面包
class Bread extends Snack {
    price() {
        return 5.00
    }
    name() {
        return 'Bread'
    }
}

// 套餐
class Meal {
    constructor() {
        this.items = []
    }
    addItem(item) {
        this.items.push(item);
    }
    getCost() {
        let cost = 0.0;
        for (const item of this.items) {
            cost += item.price();
        }
        return cost;
    }
    showItems() {
        for (const item of this.items) {
            const nameStr = "Item : " + item.name();
            const packStr = "Packing : " + item.packing().pack();
            const priceStr = "Price : " + item.price();
            console.log(`${nameStr},${packStr},${priceStr}`);
        }
    }
}

//  建造套餐
class MealBuilder {
    prepare2People() {
        const meal = new Meal();
        meal.addItem(new Coke());
        meal.addItem(new Tea());
        meal.addItem(new Bread());
        meal.addItem(new FrenchFries());
        return meal;
    }
    prepare1People() {
        const meal = new Meal();
        meal.addItem(new Coke());
        meal.addItem(new FrenchFries());
        return meal;
    }
}

const mealBuilder = new MealBuilder();
const people2 = mealBuilder.prepare2People();
people2.showItems();
console.log("Total Cost: " + people2.getCost());
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115

输出

Item : Coke,Packing : Bottle,Price : 3
Item : Tea,Packing : Bottle,Price : 5
Item : Bread,Packing : WoodenBowl,Price : 5
Item : FrenchFries,Packing : WoodenBowl,Price : 15
Total Cost: 28
1
2
3
4
5

# 原型模式

# 概念

  • 原型模式是一种创建对象的方式
  • 利用实例来描述对象,用实例作为定义对象和继承的基础
  • 用原型模式的优势是使用更小的代价来创建对象,通过原型引用的方式而不是开辟新的空间

JS创建对象的方式就是原型引用:

  • 模拟new实现
  • 原型与原型链
Edit this page (opens new window)
Last Updated: 2022/5/15 12:46:34