JavaScript设计模式系列 ---- 工厂模式与单例模式

1,854 阅读5分钟

设计模式

设计模式 ---> 解决问题的套路

  • 在开发中总结的一套方法,专门用来解决一类问题

  • 要求:设计一套系统需要设计模式(架构师)

  • 来源: 建筑行业-设计模式的四人帮

  • 常见的设计模式: 单粒(例)模式, 代理委托模式,观察者模式,中介模式

  • 推荐书籍: 《设计模式》《大话设计模式》《大话数据结构》

  • 编程就是: 数据结构 + 算法

工厂模式

工厂模式:用来创建对象的一种最常用的设计模式。区分为简单工厂模式、工厂方法模式、抽象工厂模式

简单工厂模式

  • 核心步骤:
    • 1.提供一个父构造函数(开了一家工厂)
    • 2.设置父构造函数的原型对象(产品公共的一些东西)
    • 3.在父构造函数上提供一个静态的工厂方法(生产产品)
    • 4.定制合作伙伴
    • 5.使用父构造函数的静态工厂方法创建对象
  • 实现
    // 1.提供一个父构造函数(开了一家工厂)
    function PhoneMake (){
        
    }
    // 2.设置父构造函数的原型对象(产品公共的一些东西)
    PhoneMake.prototype.logDes = function (){
        
    }
    // 3.在父构造函数上提供一个静态的工厂方法(生产产品)
    PhoneMake.factory = function (){
        console.log(this.des)
    }
    // 4.定制合作伙伴
    PhoneMake.iphone = function(){
        this.des = ''
    }
    PhoneMake.vivo = function(){
        this.des = ''
    
    PhoneMake.oppo = function(){
        this.des = ''
    }
    // 5.使用父构造函数的静态工厂方法创建对象
     var iphone = PhoneMake.factory('iPhone');
    iphone.logDes();
    
    var vivo = PhoneMake.factory('vivo');
    vivo.logDes();
    
    var oppo = PhoneMake.factory('oppo');
    oppo.logDes();
    
    var meizu = PhoneMake.factory('meizu');
    meizu.logDes();

单粒(例)模式

一个类创建出来的对象都是同一个对象

单例模式使用的场景

比如线程池、全局缓存等。我们所熟知的浏览器的window对象就是一个单例,在JavaScript开发中,对于这种只需要一个的对象,我们的实现往往使用单例。

单粒实现方式01(全局变量)

  • 步骤
      1. 提供一个全局变量(instance)
    • 2.提供一个构造函数
    • 3.判断instance是否有值,有值就直接返回
    • 4.没有就把this赋值给instance
    • 5.设置属性和方法
// 1.提供一个全局变量
var instance;
// 2.提供一个构造函数
function Person(){
    // 3.判断全局变量是否有值,如果有值就直接返回
    if(instance){ //第二次以上
        return instance;
    }
    // 第一个创建对象
    // 4,如果没有值,就把this赋值给instance
    instance = this;
    // 5.设置属性和方法
    this.name = '默认';
}

var p1 = new Person();
var p2 = new Person();
instance = 'demo'
var p3 = new Person();

console.log(p1 === p2); // true
console.log(p3); // Person{}  新创建的对象

注意:return 的值如果不是引用类型的数据,那么return返回的是默认创建的对象

缺点:全局变量在整一个作用域都可以被访问或者修改,一旦被修改,创建出来的对象就不再是之前的单粒对象

单粒实现方式02(静态属性)

// 1.提供一个构造函数
function Person(){
    // 2.判断构造函数静态属性instance是否有值,如果有值就直接返回
    if(Person.instance){ //第二次以上
        return Person.instance;
    }
    // 第一个创建对象
    // 3,如果没有值,就把this赋值给instance
    Person.instance = this;
    // 4.设置属性和方法
    this.name = '默认';
}

var p1 = new Person();
var p2 = new Person();
console.log(p1 == p2);// true

Person.instance = 'demo';
var p4 = new Person();
console.log(p4); // person{}

好处:instance 不是全局变量,不容易被修改

缺点:静态属性仍然能被修改

单粒实现方式03(惰性函数)

  • 步骤:
    • 1.提供一个构造函数
    • 2.提供一个封闭作用域的私有变量
    • 3.利用惰性函数定义更新函数
    • 4.把this赋值给instance
    • 5.设置属性和方法
// 1.提供一个构造函数
function Person(){
    // 2.提供一个封闭作用域的私有变量
    var  instance;
    // 3.利用惰性函数定义更新函数
    Person = function (){
        return instance;
    }
    // 第一个创建对象
    // 4.把this赋值给instance
    instance = this;
    // 5.设置属性和方法
    this.name = '默认';
}

//var p1 = new Person();
//var p2 = new Person();
//console.log(p1 == p2);// true

Person.prototype.des = 'des';
var p3 = new Person();
Person.prototype.hi = 'hi';
var p4 = new Person();

console.log(p3.des); // des
console.log(p4.des); // des
console.log(p3.hi); // undefined
console.log(p4.hi); // undefined

console.log(p3.constructor == Person);// false

  • 问题:
    • 1.创建对象之后设置的原型对象和单粒对象的原型对象,不是同一个对象
      • (广义理解: 第一个对象创建出后,其后的原型对象是新创建的Person,不是旧的)
    • 2.单粒对象的构造器属性执行指向旧的构造函数

惰性函数实现单粒改进 04

  • 步骤
    • 1.提供一个构造函数
    • 2.在构造函数内部声明一个私有变量instance
    • 3.利用惰性函数更新构造函数
    • 4.设置新构造函数的原型对象是旧构造函数的原型对象(原型式继承)
    • 4*.设置新构造函数的原型对象是旧构造函数的实例对象(原型链继承better)
    • 5.利用新构造函数创建对象并赋值给instance
    • 6.修正构造器属性
    • 7.通过instance设置属性或方法
    • 8.返回instance
// 1.提供一个构造函数
function Person(){
    // 2.在构造函数内部声明一个私有变量instance
    var instance;
    // 3.利用惰性函数更新构造函数
    Person = function(){
        return instance;
    }
    // 4.设置新构造函数的原型对象是旧构造函数的原型对象(原型式继承)
    // Person.prototype = this.__proto__;
    
    // *4.更优原型链继承
    Person.prototype = this;
    
    // 5.利用新构造函数创建对象并赋值给instance
    instance = new Person();  
    // 6.修正构造器属性
    instance.constructor = Person ; 
    // 7.通过instance设置属性或方法
    instance.name = '默认';
    // 8.返回instance
    return instance;
}
//var p1 = new Person();
//var p2 = new Person();
//console.log(p1==p2); // true


Person.prototype.des = 'des';
var p3 = new Person();
Person.prototype.hi = 'hi';
var p4 = new Person();

console.log(p3.des); // des
console.log(p4.des); // des
console.log(p3.hi); // hi
console.log(p4.hi); // hi

console.log(p3.constructor == Person);// true

图解

参照文献:工厂模式 juejin.cn/post/684490…