放肆青春的博客
首页
前端
算法
网络
面试
技术
后端
运维
杂项
数据库
工具
网址
电脑
个人
文章
  • 分类
  • 标签
  • 归档
github (opens new window)
gitee (opens new window)

放肆青春

一个前端菜鸟的技术成长之路
首页
前端
算法
网络
面试
技术
后端
运维
杂项
数据库
工具
网址
电脑
个人
文章
  • 分类
  • 标签
  • 归档
github (opens new window)
gitee (opens new window)
  • 技术汇总

    • 技术总结
    • 技术文章
  • 技术术语

  • 技术方案

    • 技术场景汇总
    • 技术方案

    • 前端方案

    • 三方平台

    • 图片方案

    • 文件方案

  • 技术点

  • 设计模式及原则

    • 设计模式
    • 创建型模式

      • 单例模式
      • 工厂模式
        • 工厂模式
        • 简单工厂模式
          • ES5 代码实现
          • ES6 代码实现
          • 简单工厂函数适用场景
          • 简单工厂函数不适用场景
        • 工厂方法模式
          • 安全模式类
          • ES5 实现
          • ES6 实现
        • 抽象工厂模式
          • 代码实现
        • 工厂模式区别
        • 工厂模式实例
    • 结构型模式

    • 行为型模式

    • 设计原则
  • technology
放肆青春
2021-04-15

工厂模式

# 工厂模式

概念 工厂模式是用来创建对象的一种最常用的设计模式(创建性)我们不暴露创建对象的具体逻辑,而是将逻辑封装在一个函数中,那么这个函数就可以被看作一个工厂

分类 工厂模式根据抽象程度又分为三种:简单工厂模式、工厂方法模式和抽象工厂模式

# 简单工厂模式

简单工厂模式又叫 静态方法模式

因为工厂类中定义了一个静态方法用于创建对象。简单工厂让使用者不用知道具体的参数就可以创建出所需的 ”产品“ 类,即使用者可以直接消费产品而不需要知道产品的具体生产细节。

# ES5 代码实现

function Role(options) {
  this.role = options.role;
  this.permissions = options.permissions;
}
Role.prototype.show = function() {
  var str = "是一个" + this.role + ", 权限:" + this.permissions.join(", ");
  console.log(str);
};

function simpleFactory(role) {
  switch (role) {
    case "admin":
      return new Role({
        role: "管理员",
        permissions: [
          "设置",
          "删除",
          "新增",
          "创建",
          "开发",
          "推送",
          "提问",
          "评论",
        ],
      });
      break;
    case "developer":
      return new Role({
        role: "开发者",
        permissions: ["开发", "推送", "提问", "评论"],
      });
      break;
    default:
      throw new Error("参数只能为 admin 或 developer");
  }
}

// 实例
const xm = simpleFactory("admin");
xm.show();

const xh = simpleFactory("developer");
xh.show();

const xl = simpleFactory("guest");
xl.show();
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

# ES6 代码实现

class SimpleFactory {
  constructor(opt) {
    this.role = opt.role;
    this.permissions = opt.permissions;
  }

  // 静态方法
  static create(role) {
    switch (role) {
      case "admin":
        return new SimpleFactory({
          role: "管理员",
          permissions: [
            "设置",
            "删除",
            "新增",
            "创建",
            "开发",
            "推送",
            "提问",
            "评论",
          ],
        });
        break;
      case "developer":
        return new SimpleFactory({
          role: "开发者",
          permissions: ["开发", "推送", "提问", "评论"],
        });
        break;
      default:
        throw new Error("参数只能为 admin 或 developer");
    }
  }

  show() {
    const str = `是一个${this.role}, 权限:${this.permissions.join(", ")}`;
    console.log(str);
  }
}

// 实例
const xm = SampleFactory.create("admin");
xm.show();

const xh = SampleFactory.create("developer");
xh.show();

const xl = SampleFactory.create("guest");
xl.show();
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

# 简单工厂函数适用场景

  1. 正确传参,就可以获取所需要的对象,无需知道内部实现细节;

  2. 内部逻辑(工厂函数)通过传入参数判断实例化还是使用哪些类;

  3. 创建对象数量少(稳定),对象的创建逻辑不复杂;

# 简单工厂函数不适用场景

  1. 当需要添加新的类时,就需要修改工厂方法,这违背了开放封闭原则(OCP, 对扩展开放、对源码修改封闭)。正所谓成也萧何败也萧何。函数 create 内包含了所有创建对象(构造函数)的判断逻辑代码,如果要增加新的构造函数还需要修改函数 create(判断逻辑代码),当可选参数 role 变得更多时,那函数 create 的判断逻辑代码就变得臃肿起来,难以维护。

  2. 不适用创建多类对象;

# 工厂方法模式

工厂方法模式(Factory Method Pattern)又称为工厂模式,也叫多态工厂(Polymorphic Factory)模式,它属于类创建型模式。

将实际创建对象工作推迟到子类当中,核心类就成了抽象类。这样添加新的类时就无需修改工厂方法,只需要将子类注册进工厂方法的原型对象中即可。

# 安全模式类

安全模式就是麻烦自己,方便他人的利他主义模式

可以屏蔽使用类的错误造成的错误

function Factory() {
  if (!(this instanceof Factory)) {
    return new Factory();
  }
}
Factory.prototype.show = function() {
  console.log("factory show");
};
var f = new Factory();
f.show();
1
2
3
4
5
6
7
8
9
10

# ES5 实现

ES5 没有像传统创建类的方式那样创建抽象类,所以工厂方法模式只需参考其核心思想即可。可将工厂方法看做一个实例化对象工厂类(采用安全模式类),将创建对象的基类放在工厂方法类的原型中即可。当需要添加新类时,只需挂载在 FunctionFactory.prototype 上,无需修改工厂方法,也实现了 OCP 原则。

// 0.0.2/es5.function.factory.js
function FunctionFactory(role) {
  if (!(["admin", "developer"].indexOf(role) > -1)) {
    throw new Error("参数只能为 admin 或 developer");
  }

  // 安全的工厂方法
  if (this instanceof FunctionFactory) {
    return this[role]();
  }
  return new FunctionFactory(role);
}
FunctionFactory.prototype.show = function() {
  var str = "是一个" + this.role + ", 权限:" + this.permissions.join(", ");
  console.log(str);
};
FunctionFactory.prototype.admin = function(permissions) {
  this.role = "管理员";
  this.permissions = [
    "设置",
    "删除",
    "新增",
    "创建",
    "开发",
    "推送",
    "提问",
    "评论",
  ];
};
FunctionFactory.prototype.developer = function(permissions) {
  this.role = "开发者";
  this.permissions = ["开发", "推送", "提问", "评论"];
};

var xm = FunctionFactory("admin");
xm.show();

var xh = new FunctionFactory("developer");
xh.show();

var xl = new FunctionFactory("guest");
xl.show();
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

# ES6 实现

由于 ES6 中还没有 abstract,就用 new.target 来模拟出抽象类(new.target 指向被 new 执行的构造函数),判断 new.target 是否指向了抽象类,如果是就报错。

class FunctionFactoryBase {
  // 抽象类
  constructor(role) {
    if (new.target === FunctionFactoryBase) {
      throw new Error("抽象类不能实例");
    }
    this.role = role;
  }
}

class FunctionFactory extends FunctionFactoryBase {
  // 子类
  constructor(role) {
    super(role);
  }

  static create(role) {
    switch (role) {
      case "admin":
        return new FunctionFactory({
          role: "管理员",
          permissions: [
            "设置",
            "删除",
            "新增",
            "创建",
            "开发",
            "推送",
            "提问",
            "评论",
          ],
        });
        break;
      case "developer":
        return new FunctionFactory({
          role: "开发者",
          permissions: ["开发", "推送", "提问", "评论"],
        });
        break;
      default:
        throw new Error("参数只能为 admin 或 developer");
    }
  }

  show() {
    const { role, permissions } = this.role;
    const str = `是一个${role}, 权限:${permissions.join(", ")}`;
    console.log(str);
  }
}

// let xl = new FunctionFactoryBase(); // 此行会报错,注释后方可正常执行后面

let xm = FunctionFactory.create("admin");
xm.show();

let xh = FunctionFactory.create("developer");
xh.show();

let xl = FunctionFactory.create("guest");
xl.show();
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

# 抽象工厂模式

抽象工厂只留对外的口子,不做事,留给外界覆盖(子类重写接口方法以便创建的时候指定自己的对象类型)。主要用于对产品类簇的创建,不直接生成实例(简单工厂模式和工厂方法模式都是生成实例)。

抽象类是一种声明但不能使用的类,子类必须先实现其方法才能调用;

可以在抽象类中定义一套规范,供子类去继承实现;

# 代码实现

// 抽象工厂
function AbstractFactory(subType, superType) {
  if (typeof AbstractFactory[superType] === "function") {
    //缓存类
    function F() {}
    //继承父类属性和方法
    F.prototype = new AbstractFactory[superType]();
    //将子类 constructor 指向子类(自己)
    subType.prototype.constructor = subType;
    //子类原型继承缓存类(父类)
    subType.prototype = new F();
  } else {
    //不存在该抽象类抛出错误
    throw new Error("抽象类不存在");
  }
}

// 抽象类
AbstractFactory.Phone = function() {
  this.type = "Phone";
};
AbstractFactory.Phone.prototype = {
  showType: function() {
    return new Error("Phone 抽象方法 showType 不能调用");
  },
  showPrice: function() {
    return new Error("Phone 抽象方法 showPrice 不能调用");
  },
  showColor: function() {
    return new Error("Phone 抽象方法 showColor 不能调用");
  },
};

AbstractFactory.Pad = function() {
  this.type = "Pad";
};
AbstractFactory.Pad.prototype = {
  showType: function() {
    return new Error("Pad 抽象方法 showType 不能调用");
  },
  showPrice: function() {
    return new Error("Pad 抽象方法 showPrice 不能调用");
  },
  showColor: function() {
    return new Error("Pad 抽象方法 showColor 不能调用");
  },
};

// 抽象工厂实现对抽象类的继承
function Iphone(type, price, color) {
  this.type = type;
  this.price = price;
  this.color = color;
}

//抽象工厂实现对 Phone 抽象类的继承
AbstractFactory(Iphone, "Phone");
Iphone.prototype.showType = function() {
  return this.type;
};
Iphone.prototype.showPrice = function() {
  return this.price;
};
Iphone.prototype.showColor = function() {
  return this.color;
};

function Ipad(type, price, color) {
  this.type = type;
  this.price = price;
  this.color = color;
}
AbstractFactory(Ipad, "Pad");
Ipad.prototype.showType = function() {
  return this.type;
};
Ipad.prototype.showPrice = function() {
  return this.price;
};
Ipad.prototype.showColor = function() {
  return this.color;
};

// 实例
var iphone5s = new Iphone("iphone 5s", 3000, "白色");
console.log(
  "今天刚买了" +
    iphone5s.showType() +
    ",价格是" +
    iphone5s.showPrice() +
    "," +
    iphone5s.showColor()
);

var iphone8s = new Iphone("iphone 8s", 8000, "白色");
console.log(
  "今天刚买了" +
    iphone8s.showType() +
    ",价格是" +
    iphone8s.showPrice() +
    "," +
    iphone8s.showColor()
);

var ipad = new Ipad("ipad air", 2000, "骚红色");
console.log(
  "今天刚买了" +
    ipad.showType() +
    ",价格是" +
    ipad.showPrice() +
    "," +
    ipad.showColor()
);
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

# 工厂模式区别

简单工厂 : 使用一个工厂对象用来生产同一等级结构中的任意产品。(不支持拓展增加产品)

工厂方法 : 使用多个工厂对象用来生产同一等级结构中对应的固定产品。(支持拓展增加产品)

抽象工厂 : 使用多个工厂对象用来生产不同产品族的全部产品。(不支持拓展增加产品;支持增加产品族)

# 工厂模式实例

  1. jQuery 源码-工厂模式

参考:https://juejin.cn/post/6844903895546724366 (opens new window)

更新时间: 12/22/2021, 6:20:36 PM
单例模式
装饰器模式

← 单例模式 装饰器模式→

最近更新
01
前端权限管理
02-24
02
vue2指令
02-24
03
vue2 hook
02-24
更多文章>
Theme by Vdoing | Copyright © 2019-2022 放肆青春
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式