JavaScript工厂模式

JavaScript工厂模式

首先须要说一下工厂模式。工厂模式根据抽象程度的不一样分为三种数据库

  • 简单工厂模式
  • 工厂方法模式
  • 抽象工厂模式

1.简单工厂模式

简单工厂模式:又称为静态工厂方法模式,它属于类建立型模式。
在简单工厂模式中,能够根据参数的不一样返回不一样类的实例。
由工厂对象决定建立某一种产品对象类的实例。缓存

// #简单工厂模式第一种
/**
 * 足球类
 */
var FootBall = function  () {
    this.play = function () {
        console.log('我在踢足球');
    }
}

/**
 * 篮球类
 */
var BasketBall = function  () {
    this.play = function () {
        console.log('我在打篮球');
    }
}

var football = new FootBall();
football.play();
var basketball = new BasketBall();
basketball.play();

/**
 * 球类工厂
 */
var Ball = function(name) {
    switch (name) {
        case '足球':
            return new FootBall();
        break;
        case '篮球':
            return new BasketBall();
        break;
    }
}
var football =  Ball('足球');
football.play();
var basketball =  Ball('篮球');
basketball.play();

// #简单工厂模式第一种end

这段案例能够简单的这么去理解,假设咱们须要多个球,咱们但愿在使用球的时候,只须要告诉管理员咱们须要的球的类型,不须要一个个去找对应的球这个管理员就相对于工厂函数。安全

简单讲就是使用简单工厂模式,那么你就不须要关心它的具体实现,你只须要知道你要使用的类型,那么工厂函数会自动帮你去作对应的事情函数

// #简单工厂模式第二种

/**
 * 球类工厂
 */
var Ball = function(name) {
    // 建立一个对象,对对象扩展扩展属性还有方法
    var o = new Object();
    o.name = name;
    //默认的方法 若是在加上一个羽毛球类,这时候就不须要补充play方法
    o.play = function () {
        console.log('我在打'+name);
    }
    if (name === '足球') {
        o.play = function () {
            console.log('我在踢'+name);
        }
    }else if (name === '篮球') {
        o.play = function () {
            console.log('我在打'+name);
        }
    }
    // 将对象返回
    return o;
}
var football =  Ball('足球');
football.play();
var basketball =  Ball('篮球');
basketball.play();

// #简单工厂模式第二种end

这段案例是用对象的方式代替多个类,把相同点抽离出来,this

不一样点在一一作类型判断,这样也是简单工厂模式实现的另外一种方式prototype

简单工厂模式的优势:设计

  • 工厂类含有必要的判断逻辑,能够决定在何时建立哪个产品类的实例,客户端能够免除直接建立产品对象的责任,而仅仅“消费”产品;简单工厂模式经过这种作法实现了对责任的分割,它提供了专门的工厂类用于建立对象
  • 客户端无须知道所建立的具体产品类的类名,只须要知道具体产品类所对应的参数便可,对于一些复杂的类名,经过简单工厂模式能够减小使用者的记忆量。

简单工厂模式的缺点code

  • 因为工厂类集中了全部产品建立逻辑,一旦不能正常工做,整个系统都要受到影响。
  • 使用简单工厂模式将会增长系统中类的个数,在必定程序上增长了系统的复杂度和理解难度。
  • 系统扩展困难,一旦添加新产品就不得不修改工厂逻辑,在产品类型较多时,有可能形成工厂逻辑过于复杂,不利于系统的扩展和维护。

简单工厂模式的适用状况对象

在如下状况下可使用简单工厂模式:继承

  • 工厂类负责建立的对象比较少:因为建立的对象较少,不会形成工厂方法中的业务逻辑太过复杂。
  • 客户端只知道传入工厂类的参数,对于如何建立对象不关心:客户端既不须要关心建立细节,甚至连类名都不须要记住,只须要知道类型所对应的参数。

简单工厂模式总结

  • 简单工厂模式的要点在于:当你须要什么,只须要传入一个正确的参数,就能够获取你所须要的对象,而无须知道其建立细节。
  • 简单工厂模式最大的优势在于实现对象的建立和对象的使用分离,将对象的建立交给专门的工厂类负责,可是其最大的缺点在于工厂类不够灵活,增长新的具体产品须要修改工厂类的判断逻辑代码,并且产品较多时,工厂方法代码将会很是复杂。

2.工厂方法模式

工厂方法模式:又称为工厂模式,也叫虚拟构造器模式或者多态工厂模式它属于类建立型模式。在工厂方法模式中,工厂父类负责定义建立产品对象的公共接口,而工厂子类则负责生成具体的产品对象,这样作的目的是将产品类的实例化操做延迟到工厂子类中完成,即经过工厂子类来肯定究竟应该实例化哪个具体产品类这样解释可能会有点抽象。

// # 工厂方法模式
// 安全模式建立工厂类
var Ball = function (type,name) {
    /**
     * 安全模式 Ball也能够运行处new Ball的效果
     */
    if(this instanceof Ball) {
        var s = new this[type](name);
        return s;
    }else {
        return new Ball(type,name);
    }
}
// 工厂原型中设置建立全部类型数据对象的基类
Ball.prototype = {
    basketBall: function(name) {
        this.play = function() {
            console.log('我在打'+name);
        }
    },
    footBall: function(name) {
        this.play = function() {
            console.log('我在踢'+name);
        }
    },
    badmintonBall: function(name) {
        this.play = function() {
            console.log('我在打'+name);
        }
    },
    // ....
}
var football = new Ball('footBall','足球');
football.play();
var basketball = new Ball('basketBall','篮球');
basketball.play();
var badmintonball = new Ball('badmintonBall','羽毛球');
badmintonball.play();

// # 工厂方法模式end

这段案例是这么去理解的,咱们先建立一个球类工厂,这个球类工厂是一个抽象的,不作具体的实现,而后咱们在这个球类工厂里面在去定义对应的球类实现,如篮球,羽毛球,足球等实现,在工厂方法模式中,抽象类工厂只是负责定义一个对外的公共接口,而工厂子类则负责生成具体的产品对象。

这样作的目的是将产品类的实例化操做延迟到工厂子类中完成,即经过工厂子类来肯定究竟应该实例化哪个具体产品类若是这时候在出现一个新的球类运动,只须要为这种新类型的球类建立一个具体的球类实现就能够,这一特色无疑使得工厂方法模式具备超越简单工厂模式的优越性,更加符合“开闭原则”

上面案例包含了一个安全模式的知识点

// 安全模式建立工厂类
var Ball = function (type,name) {
    /**
     * 安全模式 Ball也能够运行处new Ball的效果
     */
    if(this instanceof Ball) {
        var s = new this[type](name);
        return s;
    }else {
        return new Ball(type,name);
    }
}

这段代码主要解决的问题是,有些同窗使用工厂类的时候,忘记使用关键字new,得不到预期想要的效果这边的解决方案就是,在构造函数开始时先判断当前对象this指代是否是当前工厂类,若是不是则经过new关键字建立对象返回,这样就能够实现不使用new关键词也能够达到相同的效果了

工厂方法模式的优势:

  • 在工厂方法模式中,工厂方法用来建立客户所须要的产品,同时还向客户隐藏了哪一种具体产品类将被实例化这一细节,用户只须要关心所需产品对应的工厂,无须关心建立细节,甚至无须知道具体产品类的类名。
  • 基于工厂角色和产品角色的多态性设计是工厂方法模式的关键。它可以使工厂能够自主肯定建立何种产品对象,而如何建立这个对象的细节则彻底封装在具体工厂内部。工厂方法模式之因此又被称为多态工厂模式,是由于全部的具体工厂类都具备同一抽象父类。
  • 使用工厂方法模式的另外一个优势是在系统中加入新产品时,无须修改抽象工厂和抽象产品提供的接口,无须修改客户端,也无须修改其余的具体工厂和具体产品,而只要添加一个具体工厂和具体产品就能够了。这样,系统的可扩展性也就变得很是好,彻底符合“开闭原则”。

工厂方法模式的缺点:

  • 在添加新产品时,须要编写新的具体产品类,并且还要提供与之对应的具体工厂类,系统中类的个数将成对增长,在必定程度上增长了系统的复杂度,有更多的类须要编译和运行,会给系统带来一些额外的开销。
  • 因为考虑到系统的可扩展性,须要引入抽象层,在客户端代码中均使用抽象层进行定义,增长了系统的抽象性和理解难度

工厂方法模式的适用状况

在如下状况下可使用工厂方法模式:

  • 一个类不知道它所须要的对象的类:在工厂方法模式中,客户端不须要知道具体产品类的类名,只须要知道所对应的工厂便可,具体的产品对象由具体工厂类建立;客户端须要知道建立具体产品的工厂类。
  • 一个类经过其子类来指定建立哪一个对象:在工厂方法模式中,对于抽象工厂类只须要提供一个建立产品的接口,而由其子类来肯定具体要建立的对象,利用面向对象的多态性和里氏代换原则,在程序运行时,子类对象将覆盖父类对象,从而使得系统更容易扩展。
  • 将建立对象的任务委托给多个工厂子类中的某一个,客户端在使用时能够无须关心是哪个工厂子类建立产品子类,须要时再动态指定,可将具体工厂类的类名存储在配置文件或数据库中。

工厂方法模式总结

工厂方法模式是简单工厂模式的进一步抽象和推广。因为使用了面向对象的多态性,工厂方法模式保持了简单工厂模式的优势,并且克服了它的缺点。在工厂方法模式中,核心的工厂类再也不负责全部产品的建立,而是将具体建立工做交给子类去作。这个核心类仅仅负责给出具体工厂必须实现的接口,而不负责产品类被实例化这种细节,这使得工厂方法模式能够容许系统在不修改工厂角色的状况下引进新产品。
工厂方法模式的主要优势是增长新的产品类时无须修改现有系统,并封装了产品对象的建立细节,系统具备良好的灵活性和可扩展性;其缺点在于增长新产品的同时须要增长新的工厂,致使系统类的个数成对增长,在必定程度上增长了系统的复杂性。

3.抽象工厂模式

抽象工厂模式:经过对类的工厂抽象使其业务用于对产品类簇的建立,而不是负责建立某一类产品的实例,属于对象建立型模式。

抽象类一直出如今咱们的文章中,那么这边先来解释一下什么是抽象类

抽象类是一种声明但不能使用的类,当你使用时就会报错,在JavaScript中abstract仍是一个保留字,因此目前来讲还不能像
传统面向对象语言那么轻松的去建立抽象类.

不过JavaScript有本身的实现方式,能够模拟出抽象类

来一段代码

// 抽象类的介绍
var Ball = function () {}
Ball.prototype = {
    play: function () {
        return new Error('抽象方法不能调用');
    }
}

解释:

咱们能够看到建立的Ball类其实什么都不能作,建立时没有任何属性,原型定义的方法也不能使用,不然就会报错。可是在继承上倒是颇有用的,
由于定义了一种类,并定义了该类所具有的方法,若是没有在子类中重写这写方法,那么调用的时候就会报错。

这一特色能够很好的提醒子类去重写这一方法,否则会在调用的时候提示错误那么在了解了什么是抽象类的状况下,咱们在来比较一下工厂方法模式与抽象工厂模式的不一样点,以方便咱们更好的去理解抽象工厂模式

工厂方法模式与抽象工厂模式的对比

在工厂方法模式中具体工厂负责生产具体的产品,每个具体工厂对应一种具体产品,工厂方法也具备惟一性,通常状况下,一个具体工厂中只有一个工厂方法或者一组重载的工厂方法。可是有时候咱们须要一个工厂能够提供多个产品对象,而不是单一的产品对象。

为了更清晰地理解抽象工厂模式,须要先引入两个概念:

  • 产品等级结构 :产品等级结构即产品的继承结构,如一个抽象类是电视机,其子类有海尔电视机、海信电视机、TCL电视机,则抽象电视机与具体品牌的电视机之间构成了一个产品等级结构,抽象电视机是父类,而具体品牌的电视机是其子类。
  • 产品族 :在抽象工厂模式中,产品族是指由同一个工厂生产的,位于不一样产品等级结构中的一组产品,如海尔电器工厂生产的

海尔电视机、海尔电冰箱,海尔电视机位于电视机产品等级结构中,海尔电冰箱位于电冰箱产品等级结构中。

抽象工厂模式与工厂方法模式最大的区别在于,工厂方法模式针对的是一个产品等级结构,而抽象工厂模式则须要面对多个产品等级结构,一个工厂等级结构能够负责多个不一样产品等级结构中的产品对象的建立。当一个工厂等级结构能够建立出分属于不一样产品等级结构的一个产品族中的全部对象时,抽象工厂模式比工厂方法模式更为简单、有效率。

这句话比较简单的理解方式就是:若是一个工厂只须要生产一个类型的产品好比说电视机,那么用工厂方法模式是比较合理的,若是这个工厂又须要成产电视机,又须要生产冰箱之类的,那么这时候用工厂抽象模式就是最合适的。

// # 抽象工厂模式
var Sport = function(subType, superType) {
    if( typeof Sport[superType] === 'function'){
        // 缓存类
        function F() {};
        // 继承父类属性和方法
        F.prototype = new Sport[superType]();
        // 将子类constructor 指向子类
        subType.constructor = subType;
        // 子类原型继承 “父类”
        subType.prototype = new F(); 
    }else {
        // 不存在抽象类则抛出错误
        throw new Error('未建立该抽象类');
    }
}

// 球类运动抽象类
Sport.Ball = function () {
    this.type = 'ball';
}
Sport.Ball.prototype = {
    play: function () {
        return new Error('抽象方法不能调用');
    }
}

// 力量型运动抽象类
Sport.Power = function () {
    this.type = 'power';
}
Sport.Power.prototype = {
    play: function () {
        return new Error('抽象方法不能调用');
    }
}

// 速度型运动抽象类
Sport.Speed = function () {
    this.type = 'speed';
}
Sport.Speed.prototype = {
    play: function () {
        return new Error('抽象方法不能调用');
    }
}

// 篮球类
var BasketBall = function (name) {
    this.name = name;
};
// 抽象工厂实现对球类运动的继承
Sport(BasketBall,'Ball');
BasketBall.prototype.play = function () {
    console.log('我在玩'+this.name);
}


// 举重类
var WeightLifting = function (name) {
    this.name = name;
};
// 抽象工厂实现对力量型运动的继承
Sport(WeightLifting,'Power');
WeightLifting.prototype.play = function () {
    console.log('我在玩'+this.name);
}

// 跑步类
var Running = function (name) {
    this.name = name;
};
// 抽象工厂实现对速度运动的继承
Sport(Running,'Speed');
Running.prototype.play = function () {
    console.log('我在'+this.name);
}

// 抽象工厂模式实现
var basketBall = new BasketBall('篮球');
console.log(basketBall.type);//ball
basketBall.play();
var weightLifting = new WeightLifting('举重');
console.log(weightLifting.type);//power
weightLifting.play();
var running = new Running('跑步');
console.log(running.type);//ball
running.play();

/** 输出结果
 * ball
 * 我在玩篮球
 * power
 * 我在玩举重
 * speed
 * 我在跑步
 */


// # 抽象工厂模式end

这段栗子先是建立一个运动类的抽象工厂,经过这个暴露外部调用的接口,传递2个参数,一个是subType,当前实例化的对象,也就是子类,
一个是superType,须要继承的父类(抽象类)的名称,在工厂函数中实现了子类对父类的继承。

在继承过程当中有一个地方须要注意,就是在对过渡类继承的时候,咱们不是继承父类原型,而是经过new关键字复制父类的一个实列,这样作的目的是过渡类不只仅继承父类的原型方法,还须要继承父类的对象属性,因此经过new关键字的方式实现了继承。

而后经过在抽象工厂类上面进行扩展对应的抽象类,也就是咱们须要经过继承的父类,我这边添加了3个抽象类Ball,Power,Speed,分别给抽象类指定了type属性,还有方法play,既然建立了抽象类,那么下面就是开始使用抽象工厂去建立子类,这边分别对Ball,Power,Speed 3个抽象类进行了实现建立了BasketBall(球类),WeightLifting(力量),Running(速度)3个子类3个子类分别对play方法进行了实现最后就是对于子类的调用实现,在实现子类调用的时候,

咱们能够获取到继承的父类当中对应的type

抽象工厂模式的优势:

当一个产品族中的多个对象被设计成一块儿工做时,它可以保证客户端始终只使用同一个产品族中的对象。

增长新的具体工厂和产品族很方便,无须修改已有系统,符合“开闭原则”。

抽象工厂模式的缺点:

开闭原则的倾斜性(增长新的工厂和产品族容易,增长新的产品等级结构麻烦)。

增长新的产品等级结构:对于增长新的产品等级结构,须要修改全部的工厂角色,包括抽象工厂类,在全部的工厂类中都须要增长生产新产品的方法,不能很好地支持“开闭原则”。

抽象工厂模式的适用状况:

在如下状况下可使用抽象工厂模式:

  • 一个系统不该当依赖于产品类实例如何被建立、组合和表达的细节,这对于全部类型的工厂模式都是重要的。
  • 系统中有多于一个的产品族,而每次只使用其中某一产品族。属于同一个产品族的产品将在一块儿使用,这一约束必须在系统的设计中体现出来。
  • 系统提供一个产品类的库,全部的产品以一样的接口出现,从而使客户端不依赖于具体实现。

抽象工厂模式总结

  • 抽象工厂模式是全部形式的工厂模式中最为抽象和最具通常性的一种形态。抽象工厂模式与工厂方法模式最大的区别在于,工厂方法模式针对的是一个产品等级结构,而抽象工厂模式则须要面对多个产品等级结构。
  • 抽象工厂模式适用状况包括:一个系统不该当依赖于产品类实例如何被建立、组合和表达的细节;系统中有多于一个的产品族,而每次只使用其中某一产品族;属于同一个产品族的产品将在一块儿使用;系统提供一个产品类的库,全部的产品以一样的接口出现,从而使客户端不依赖于具体实现。

4.三大工厂模式的关联性

  • 当抽象工厂模式中每个具体工厂类只建立一个产品对象,也就是只存在一个产品等级结构时,抽象工厂模式转换成工厂方法模式;
  • 当工厂方法模式中抽象工厂与具体工厂合并,提供一个统一的工厂来建立产品对象,并将建立对象的工厂方法设计为静态方法时,工厂方法模式退化成简单工厂模式。
注:根据实际适用状况去选择对应的工厂模式
相关文章
相关标签/搜索