Skip to content

工厂模式(工厂方法)

通过传入不同的参数来创建不同的类, 而不是直接使用 new 关键字, 好处是便于扩展

假如需求是这样的, 实现一个工具库, 可以将数据存入不同的介质中, 应该如何设计代码实现?

javascript
// 如果不使用工厂模式, 用什么就 new 什么
class FileCache {
  get() {}
  set() {}
}
class MemeoryCache {
  get() {}
  set() {}
}
class RedisCache {
  get() {}
  set() {}
}

// 这样会导致代码耦合性非常高, 在哪用就要在哪里依赖, 好处是方便简单
const fileCache = new FileCache();
const memeoryCache = new MemeoryCache();
const redisCache = new RedisCache();
javascript
// 使用工厂模式, 支持的类都通过 factory 方法来生成, 想要什么就传入对应的方法
class FileCache {
  get() {}
  set() {}
}
class MemeoryCache {
  get() {}
  set() {}
}
class RedisCache {
  get() {}
  set() {}
}

// 如果是通过方法实例化,只需要导入这个 cacheFactory, 而且如果要扩展一个新的类
// 可以直接增加 allowTypes 和对应的case和类, 可以方便扩展
function cacheFactory(type, config) {
  const allowTypes = ['file', 'memory', 'redis'];
  if (!allowTypes.includes(type)) {
    throw new TypeError('[cacheFactory]:unknown cache type');
  }
  let cacheManager = null;
  switch (type) {
    case 'file':
      cacheManager = new FileCache(config);
      break;
    case 'memory':
      cacheManager = new MemoryCache(config);
      break;
    case 'redis':
      cacheManager = new RedisCache(config);
      break;
  }
  return cacheManager;
}

单例模式

所谓单例就是这个类只能有一个实例对象, 比如数据库链接类, 比如一些全局的工具类

小知识: 在 JavaScript 面向对象中, 如果在构造函数中手动返回一个引用值, 那么 new 的结果就是引用值

ES5

javascript
// ES5 实现方式: 利用闭包
// 将唯一实例变量私有化, 也可以像 es6 一样将 _instance
// 设置到静态属性上, 两种方式都可以实现
var ConnectionManager = (function () {
  var _instance = null;
  function ConnectionManager(config) {
    if (!_instance) {
      _instance = this;
    }

    this.init(config);
    return _instance;
  }

  // 提供获取唯一实例的方法
  ConnectionManager.getInstance = function (config) {
    return new ConnectionManager(config);
  };

  // 其他操作
  ConnectionManager.prototype.init = function (config) {
    console.log('数据库链接成功', config);
  };

  return ConnectionManager;
})();

var host = '127.0.0.1';
var c1 = new ConnectionManager(host);
var c2 = new ConnectionManager(host);
var c3 = ConnectionManager.getInstance(host);
var c4 = ConnectionManager.getInstance(host);
console.log(c1 === c2); // output: true
console.log(c1 === c3); // output: true
console.log(c1 === c4); // output: true
console.log(c2 === c3); // output: true
console.log(c2 === c4); // output: true

ES6

javascript
class ConnectionManager {
  // 将唯一实例放到静态属性上
  static _instance = null;
  constructor(config) {
    if (!ConnectionManager._instance) {
      ConnectionManager._instance = this;
    }
    // 传入参数等其他操作
    this.init(config);
    return ConnectionManager._instance;
  }

  // 提供获取唯一实例的方法
  static getInstance(config) {
    return new ConnectionManager(config);
  }

  init(config) {
    console.info('数据库链接成功:', config);
  }
}

// 无论是使用 new 还是使用 getInstance 方法, 获取到的都是唯一实例
var host = '127.0.0.1';
var c1 = new ConnectionManager(host);
var c2 = new ConnectionManager(host);
var c3 = ConnectionManager.getInstance(host);
var c4 = ConnectionManager.getInstance(host);
console.log(c1 === c2); // output: true
console.log(c1 === c3); // output: true
console.log(c1 === c4); // output: true
console.log(c2 === c3); // output: true
console.log(c2 === c4); // output: true

原型模式

原型继承

Released under the MIT License.