什么是工厂模式 当去买一个 🍔 的时候,无须得到 🍔 的原材料,只需要获得到 🍔 对应工厂模式:不暴露创建对象的具体逻辑,将创建对象的方法封装到一个函数中,这个函数就是一个工厂 工厂模式按照抽象程度可以分为:1.简单工厂模式 2.工厂方法模式 3.抽象工厂模式 什么时候用工厂模式 对实例的封装,使用 new 操作符时候可以考虑用工厂模式 身边的工厂模式 $(selector) $()就是一个…

什么是工厂模式

  1. 当去买一个 🍔 的时候,无须得到 🍔 的原材料,只需要获得到 🍔
  2. 对应工厂模式:不暴露创建对象的具体逻辑,将创建对象的方法封装到一个函数中,这个函数就是一个工厂
  3. 工厂模式按照抽象程度可以分为:1.简单工厂模式 2.工厂方法模式 3.抽象工厂模式

什么时候用工厂模式

  1. 对实例的封装,使用 new 操作符时候可以考虑用工厂模式

身边的工厂模式

  1. $(selector)

    $()就是一个简单工厂模式

function jQuery() {}
jQuery.prototype.extend = function() {};
// ...
window.$ = function(selector) {
  return new jQuery(selector);
};

工厂模式的类型

简单工厂模式

function CreatePerson(name, age, sex) {
  var obj = Object.create(null);
  obj.name = name;
  obj.age = age;
  obj.sex = sex;
  obj.getData = function() {
    console.log(this.name, this.age, this.sex);
  };
  return obj;
}
function factory(name, age, sex) {
  return new CreatePerson(name, age, sex);
}
var p1 = factory('express', 21, 1);
var p2 = factory('egg', 22, 0);
p1.getData();
p2.getData();
// 输出
// express 21 1
// egg 22 0
// 简单工厂模式
// 只需要一个正确的参数,就可以得到结果,不需要知道创建的过程
// 不同用户分配不同权限
// 如果角色变多,那么就getInstance变的很庞大,比较难维护,所以适用于创建对象较少的情况
class User {
  //构造器
  constructor(option) {
    this.role = option.role;
    this.limit = option.limit;
  }

  //静态方法
  static getInstance(role) {
    switch (role) {
      case 'superAdmin':
        return new User({
          role: '超级管理员',
          limit: ['首页', '通讯录', '发现页', '应用数据', '权限管理']
        });
        break;
      case 'admin':
        return new User({
          role: '管理员',
          limit: ['首页', '通讯录', '发现页', '应用数据']
        });
        break;
      case 'user':
        return new User({
          role: '普通用户',
          limit: ['首页', '通讯录', '发现页']
        });
        break;
      default:
        throw new Error('参数错误, 可选参数:superAdmin、admin、user');
    }
  }
}
let superAdmin = User.getInstance('superAdmin');
let admin = User.getInstance('admin');
let normalUser = User.getInstance('user');
console.log(superAdmin);
console.log(admin);
console.log(normalUser);
// 输出
// role: "超级管理员", limit['首页', '通讯录', '发现页', '应用数据', '权限管理']
// role: "管理员", limit['首页', '通讯录', '发现页', '应用数据']
// role: "普通用户", limit['首页', '通讯录', '发现页']

工厂方法模式

把实际创建对象放到子类中

// 工厂方法模式
// 把实际创建对象放到子类中,父类就是一个抽象类,ES6中没有 abstract修饰符,所以可以判断 new.target==父类的构造函数,抛出异常
class User {
  //构造器
  constructor(option = {}) {
    if (new.target == User) {
      throw new Error('父类是抽象类,不能直接调用,需要重写该方法');
    }
    this.role = option.role;
    this.limit = option.limit;
  }
}
class UserFactory extends User {
  constructor(option) {
    super(option);
  }
  create(role) {
    switch (role) {
      case 'superAdmin':
        return new UserFactory({
          role: '超级管理员',
          limit: ['首页', '通讯录', '发现页', '应用数据', '权限管理']
        });
        break;
      case 'admin':
        return new UserFactory({
          role: '管理员',
          limit: ['首页', '通讯录', '发现页', '应用数据']
        });
        break;
      case 'user':
        return new UserFactory({
          role: '普通用户',
          limit: ['首页', '通讯录', '发现页']
        });
        break;
      default:
        throw new Error('参数错误, 可选参数:superAdmin、admin、user');
    }
  }
}
var userFactory = new UserFactory();
let superAdmin = userFactory.create('superAdmin');
let admin = userFactory.create('admin');
let normalUser = userFactory.create('user');
console.log(superAdmin);
console.log(admin);
console.log(normalUser);
// 输出
// role: "超级管理员", limit['首页', '通讯录', '发现页', '应用数据', '权限管理']
// role: "管理员", limit['首页', '通讯录', '发现页', '应用数据']
// role: "普通用户", limit['首页', '通讯录', '发现页']

抽象工厂模式

  1. 🌰
// 抽象工厂模式
// 有了3中角色,这三种角色的注册方式可以是qq,微信,微博,那判断这个来源就可以放在父类做,让子类继承父类方法
class User {
  //构造器
  constructor(option = {}) {
    if (new.target == User) {
      throw new Error('父类是抽象类,不能直接调用,需要重写该方法');
    }
    this.role = option.role;
    this.limit = option.limit;
    this.type = '';
  }
  getFrom(type) {
    switch (type) {
      case 'weixin':
        this.type = '来自微信';
        break;
      case 'qq':
        this.type = '来自qq';
        break;
      case 'weibo':
        this.type = '来自微博';
        break;
      default:
        throw new Error('参数错误:来自火星');
    }
  }
}
class UserFactory extends User {
  constructor(option = {}) {
    super(option);
    if (option.type) {
      this.getFrom(option.type);
    }
  }
  create(role) {
    switch (role) {
      case 'superAdmin':
        return new UserFactory({
          role: '超级管理员',
          limit: ['首页', '通讯录', '发现页', '应用数据', '权限管理'],
          type: 'weixin'
        });
        break;
      case 'admin':
        return new UserFactory({
          role: '管理员',
          limit: ['首页', '通讯录', '发现页', '应用数据'],
          type: 'qq'
        });
        break;
      case 'user':
        return new UserFactory({
          role: '普通用户',
          limit: ['首页', '通讯录', '发现页'],
          type: 'weibo'
        });
        break;
      default:
        throw new Error('参数错误');
    }
  }
}
var userFactory = new UserFactory();
let superAdmin = userFactory.create('superAdmin');
let admin = userFactory.create('admin');
let normalUser = userFactory.create('user');
console.log(superAdmin);
console.log(admin);
console.log(normalUser);
// 输出
// UserFactory {role: "超级管理员", limit: Array(5), type: "来自微信"}
// UserFactory {role: "管理员", limit: Array(4), type: "来自qq"}
// UserFactory {role: "普通用户", limit: Array(3), type: "来自微博"}
  1. 🌰
// Sub是子类,Sup是超类
function _extend(Sub, Sup) {
  // 定义一个空函数
  var F = function() {};
  // 空函数原型为超类原型
  F.prototype = Sup.prototype;
  // 实例化空函数,把超类原型引用传递给子类原型
  Sub.prototype = new F();
  // 重置子类原型构造函数为子类本身
  Sub.prototype.constructor = Sub;
  // 在子类保存超类原型,避免子类与超类耦合
  Sub.sup = Sup.prototype;
  // 检测超类原型的构造函数是否为原型本身,如果是原型本身,重置超类原型构造函数为超类本身
  if (Sup.prototype.constructor === Object.prototype.constructor) {
    Sup.prototype.constructor = Sup;
  }
}
// 大工厂
var BigFactory = function(product2) {
  this.product1 = '手机';
  this.product2 = product2;
  this.get = function() {
    console.log(`我是大工厂,我自己制作了${this.product1},我可以获取到小工厂制作的${this.product2}`);
  };
};
// 大工厂的原型方法
BigFactory.prototype = {
  constructor: BigFactory,
  // 大工厂执行小工厂的制作动作
  run: function() {
    this.make().A();
  },
  make: function() {
    // 制作由小工厂做
    throw new Error('父类是抽象类,不能直接调用,需要重写该方法');
  }
};
// 小工厂
var SmallFactory = function(product2) {
  BigFactory.call(this, product2);
};
// 小工厂继承与大工厂
_extend(SmallFactory, BigFactory);
// 小工厂原型上有一个制作动作
SmallFactory.prototype.make = function() {
  var that = this;
  var A = function() {
    console.log(`我是小工厂,我在制作${that.product2}`);
  };
  return {
    A
  };
};
var smallFactory = new SmallFactory('手机壳');
smallFactory.run();
smallFactory.get();
// 输出
// 我是小工厂,我在制作手机壳
// 我是大工厂,我自己制作了手机,我可以获取到小工厂制作的手机壳

smallFactory 是继承 BigFactory 的,smallFactory 的结构

smallFactory的结构

  1. 🌰2 的演变
class BigFactory {
  constructor(product2) {
    (this.product1 = '手机'), (this.product2 = product2);
  }
  get() {
    console.log(`我是大工厂,我自己制作了${this.product1},我可以获取到小工厂制作的${this.product2}`);
  }
  run() {
    this.make().A();
  }
  make() {
    throw new Error('父类是抽象类,不能直接调用,需要重写该方法');
  }
}
class SmallFactory extends BigFactory {
  constructor(product2) {
    super(product2);
  }
  make() {
    var A = () => {
      console.log(`我是小工厂,我在制作${this.product2}`);
    };
    return {
      A
    };
  }
}
var smallFactory = new SmallFactory('手机壳');
smallFactory.run();
smallFactory.get();
// 输出
// 我是小工厂,我在制作手机壳
// 我是大工厂,我自己制作了手机,我可以获取到小工厂制作的手机壳

工厂模式在 vue-router 的应用

// vue路由例子
// router/index.js
import Vue from 'vue';
import Router from 'vue-router';
import Login from 'login.vue';

Vue.use(Router);

export default new Router({
  routes: [
    //重定向到登录页
    {
      path: '/',
      redirect: '/login'
    },
    //登陆页
    {
      path: '/login',
      name: 'Login',
      component: Login
    }
  ]
});
// router/routerFactor.js
import A from 'a.vue';
import B from 'b.vue';
import C from 'c.vue';
import D from 'd.vue';

class User {
  //构造器
  constructor(option = {}) {
    if (new.target == User) {
      throw new Error('父类是抽象类,不能直接调用,需要重写该方法');
    }
    this.role = option.role;
    this.limit = option.limit;
    this.route = [];
  }
  setLimit() {
    for (let ele of this.limit) {
      this.route.push(User.allRoute[ele]);
    }
  }
  static allRoute = {
    // A
    a: {
      path: '/a',
      name: 'A',
      component: A
    },
    // B
    b: {
      path: '/b',
      name: 'B',
      component: B
    },
    // C
    c: {
      path: '/user',
      name: 'C',
      component: C
    },
    // D
    d: {
      path: '*',
      name: 'D',
      component: D
    }
  };
}
class UserFactory extends User {
  constructor(option) {
    super(option);
    if (option) {
      this.setLimit();
    }
  }
  create(role) {
    switch (role) {
      case 'superAdmin':
        return new UserFactory({
          role: '超级管理员',
          limit: ['a', 'b', 'c', 'd']
        });
        break;
      case 'admin':
        return new UserFactory({
          role: '管理员',
          limit: ['b', 'c', 'd']
        });
        break;
      case 'user':
        return new UserFactory({
          role: '普通用户',
          limit: ['c', 'd']
        });
        break;
      default:
        throw new Error('参数错误, 可选参数:superAdmin、admin、user');
    }
  }
}
var userFactory = new UserFactory();
let superAdmin = userFactory.create('superAdmin');
let admin = userFactory.create('admin');
let normalUser = userFactory.create('user');

// 这样就把不同权限的路由获取到了
var result1 = superAdmin.route;
var result2 = admin.route;
var result3 = normalUser.route;

参考

JavaScript 设计模式与实践--工厂模式

详解 Javascript 十大常用设计模式

暂无评论