设计模式 | 工厂模式

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调用的,因此这里没有使用安全模式。


总结一下:

  • 简单工厂模式和工厂方法模式的不同:简单工厂方法把逻辑判断和实例创建都放进一个大工厂内,而工厂方法模式中的每个产品都有一个对应的工厂
  • 工厂方法模式和抽象工厂模式的不同:抽象工厂模式在工厂方式模式的基础上改进,同一个工厂有多个产品可以创建。

本文是在转载基础上加入了自己的一些想法,若有错误,往指出~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值