ES5 简单工厂模式
let userFactory = function(role){
function User(opt) {
this.name = opt.name;
this.viewPage = opt.viewPage;
}
switch (role) {
case 'SuperAdmin':
return new SuperAdmin({ name: '超级管理员', viewPage: ['pageA','pageB','pageC'] });
break;
case 'Admin':
return new Admin({ name: '管理员', viewPage: ['pageA','pageB'] });
break;
case 'Admin':
return new NonUser({ name: '管理员', viewPage: ['pageA'] });
break;
default:
throw new Error('参数错误, 可选参数:superAdmin、admin、user')
}
}
class Admin extends User{
constructor(opt){
super(opt);
}
say(){
console.log(`i am ${this.name} i can read ${this.viewPage}`)
}
}
class SuperAdmin extends User{
constructor(opt){
super(opt);
}
say(){
console.log(`i am ${this.name} i can read ${this.viewPage}`)
}
}
class NonUser extends User{
constructor(opt){
super(opt);
}
say(){
console.log(`i am ${this.name} i can read ${this.viewPage}`)
}
}
let admin1 = userFactory('Admin')
简单工厂的优点在于,你只需要一个正确的参数,就可以获取到你所需要的对象,而无需知道其创建的具体细节。但是在函数内包含了所有对象的创建逻辑(构造函数)和判断逻辑的代码,每增加新的构造函数还需要在工厂类内部添加switch分支,这违反了开闭原则。
ES5 工厂方法模式
工厂方法模式的本意是将实际创建对象的工作推迟到子类中,这样核心类就变成了抽象类,目的就是让工厂方法只提供创建实例的语句,而不包括逻辑判断。当然,js没有抽象类或者接口的概念,因此这里只是模拟一下。
let UserFactory = function(role,nickname){
// 安全模式,将不是用new创建的实例转换
if(this instanceof UserFactory){
let user = new this[role]()
return user;
}else{
return new UserFactory(role);
}
}
UserFactory.prototype = {
SuperAdmin: function() {
this.name = "超级管理员",
this.viewPage = ['pageA','pageB','pageC']
},
Admin: function() {
this.name = "管理员",
this.viewPage = ['pageA','pageB']
},
User: function() {
this.name = '普通用户',
this.viewPage = ['pageA']
},
// 添加更多
}
// 或下面这样写
// UserFactory.prototype.Admin = function() {...}
// UserFactory.prototype.SuperAdmin = function() {...}
// ......
let admin = new UserFactory('Admin')
用ES6 改写简单工厂模式和工厂方法模式
ES6 - 简单工厂
class User{
constructor(opt){
this.name = opt.name;
this.viewPage = opt.viewPage;
}
static getInstance(role){
switch (role) {
case 'SuperAdmin':
return new Admin({ name: '超级管理员', viewPage: ['pageA','pageB','pageC'] });
break;
case 'Admin':
return new Admin({ name: '管理员', viewPage: ['pageA','pageB'] });
break;
case 'User':
return new NonUser({ name: '普通用户', viewPage: ['pageA'] });
break;
default:
throw new Error('参数错误, 可选参数:superAdmin、admin、user')
}
}
}
class Admin extends User{
constructor(opt){
super(opt);
}
say(){
console.log(`i am ${this.name} i can read ${this.viewPage}`)
}
}
class SuperAdmin extends User{
constructor(opt){
super(opt);
}
say(){
console.log(`i am ${this.name} i can read ${this.viewPage}`)
}
}
class NonUser extends User{
constructor(opt){
super(opt);
}
say(){
console.log(`i am ${this.name} i can read ${this.viewPage}`)
}
}
let admin = User.getInstance('Admin')
ES6 - 工厂方法
关于es6的工厂方法实现,这里只是做自己的尝试,毕竟js在接口/抽象方面没有定义,也没有搜到一些用es6实现的工厂方法实例。在java中,会定义抽象工厂、各个产品具体工厂、抽象产品类、具体产品类,但在Js中似乎不太好实现这样一个层次。另外,js定义对象有种泛型定义的感觉,
IUser u = new Admin() 在js中并不需要指定抽象基类/接口IUser,而是let u = new Admin。
// 产品基类
class IUser{
constructor(name,role,viewPage){
this.name = name;
this.role = role;
this.viewPage = viewPage;
}
}
// admin和superAdmin的具体产品类
class Admin extends IUser{
constructor(name){
super(name,'Admin',['pageA,pageB'])
}
}
class SuperAdmin extends IUser{
constructor(name){
super(name,'SuperAdmin',['pageA','pageB','pageC'])
}
}
// admin和superAdmin的具体工厂类
class AdminFactory{
constructor(){
this.createUser = function(name){
return new Admin(name)
}
}
}
class SuperAdminFactory{
constructor(){
this.createUser = function(name){
return new SuperAdmin(name)
}
}
}
let adminFactory = new AdminFactory();
let superAdminFactory = new SuperAdminFactory()
let admin01 = adminFactory.createUser('liuj4')
let superAdmin01 = superAdminFactory.createUser('刘德华')
看起来还有模有样…
抽象工厂模式
先说说三种工厂的区别:
- 当抽象工厂模式中每一个具体工厂类只创建一个产品对象,也就是只存在一个产品等级结构时,**抽象工厂模式转换成工厂方法模式
- 当工厂方法模式中抽象工厂与具体工厂合并,提供一个统一的工厂来创建产品对象,并将创建对象的工厂方法设计为静态方法时,工厂方法模式退化成简单工厂模式。
那么就清晰很多了,上代码
class IUser{
constructor(name,role,viewPage){
this.name = name;
this.role = role;
this.viewPage = viewPage;
}
}
// 具体产品类
class Vip1 extends IUser{
constructor(name){
super(name,'vip1',['pageA','pageB'])
}
}
class Vip2 extends IUser{
constructor(name){
super(name,'vip2',['pageA','pageB','pageC'])
}
}
// 具体工厂类 多种产品的创建方法在内
class VipFactory{
constructor(){
this.createVip1 = function(name){
return new Vip1(name)
}
this.createVip2 = function(name){
return new Vip2(name)
}
//。。。。。
}
}
let vipFactory = new VipFactory();
let vip1 = vipFactory.createVip1('liuj4') // Vip1 {name: "liuj4", role: "vip1", viewPage: Array(2)}
let vip2 =vipFactory.createVip2('刘德华'); // Vip2 {name: "刘德华", role: "vip2", viewPage: Array(3)}
另外,class语法中是不允许不适用new调用的,因此这里没有使用安全模式。
总结一下:
- 简单工厂模式和工厂方法模式的不同:简单工厂方法把逻辑判断和实例创建都放进一个大工厂内,而工厂方法模式中的每个产品都有一个对应的工厂
- 工厂方法模式和抽象工厂模式的不同:抽象工厂模式在工厂方式模式的基础上改进,同一个工厂有多个产品可以创建。
本文是在转载基础上加入了自己的一些想法,若有错误,往指出~