JavaScript设计模式--简单工厂模式

Posted 与你在巅峰相会

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JavaScript设计模式--简单工厂模式相关的知识,希望对你有一定的参考价值。

一,介绍

工厂模式创建对象(视为工厂里的产品)时无需指定创建对象的具体类。

工厂模式定义一个用于创建对象的接口,这个接口由子类决定实例化哪一个类。该模式使一个类的实例化延迟到了子类。而子类可以重写接口方法以便创建的时候指定自己的对象类型。

在这里将工厂简单分为三种:

(1)简单工厂:通过第三方的类完成松耦合的任务。
(2)复杂工厂:通过把实例化的任务交给子类来完成的,用以到达松耦合的目的。
(3)超级工厂:通过eval()来完成智能工厂。
工厂的目的:
在于判断接口最终用哪个类实例化(故与接口密不可分)。
使用工厂
最终达到的效果是:多态,和类与类之间的松耦合。

二,正文部分
工厂模式与接口是密不可分的所以我们需要先引入接口文件和继承类文件
(1)接口文件:
//定义一个静态方法来实现接口与实现类的直接检验
//静态方法不要写出Interface.prototype ,因为这是写到接口的原型链上的
//我们要把静态的函数直接写到类层次上
//(1)定义一个接口类
var Interface=function (name,methods) {//name:接口名字
    if(arguments.length<2){
        alert("必须是两个参数")
    }
    this.name=name;
    this.methods=[];//定义一个空数组装载函数名
    for(var i=0;i<methods.length;i++){
        if(typeof  methods[i]!="string"){
            alert("函数名必须是字符串类型");
        }else {
            this.methods.push( methods[i]);
        }
    }
};
Interface.ensureImplement=function (object) {
    if(arguments.length<2){
        throw  new Error("参数必须不少于2个")
        return false;
    }
    for(var i=1;i<arguments.length;i++){
        var inter=arguments[i];
        //如果是接口就必须是Interface类型
        if(inter.constructor!=Interface){
            throw  new Error("如果是接口类的话,就必须是Interface类型");
        }
        //判断接口中的方法是否全部实现
        //遍历函数集合
        for(var j=0;j<inter.methods.length;j++){
            var method=inter.methods[j];//接口中所有函数

            //object[method]传入的函数
            //最终是判断传入的函数是否与接口中所用函数匹配
            if(!object[method]||typeof object[method]!="function" ){//实现类中必须有方法名字与接口中所用方法名相同
                throw  new Error("实现类中没有完全实现接口中的所有方法")
            }
        }
    }
}

(2)继承文件

/*创建extend函数为了程序中所有的继承操作*/
//subClass:子类  superClass:超类
function extend(subClass,superClass) {
    //1,使子类原型属性等于父类的原型属性

    //初始化一个中间空对象,目的是为了转换主父关系
    var F = function () {};
    F.prototype = superClass.prototype;
    //2, 让子类继承F
    subClass.prototype = new F();
    subClass.prototype.constructor = subClass;
    //3,为子类增加属性 superClass ==》原型链的引用
    subClass.superClass = superClass.prototype;
    //4,增加一个保险,就算你的原型类是超类(Object)那么也要把你的构造函数级别降下来
    if (superClass.prototype.constructor == Object.prototype.constructor) {
        superClass.prototype.constructor = superClass;
    }
}

通过下面的例子,逐步引进工厂模式及改进工厂模式
1,工厂模式的引入,
(1)创建接口对象
  var Pet=new Interface("Pet",["eat","run","sing","register"]);

(2)定义一个宠物店类并在prototype上进行扩展
 var PetShop=function () {}
    PetShop.prototype={
        //出售宠物的方法
        sellPet:function (kind) {
            //宠物对象
            var pet;
           //宠物种类
            switch (kind){
                case  \'dog\':
                    pet=new Dog();
                break;
                case  \'cat\':
                    pet=new Cat();
                    break;
                case  \'pig\':
                    pet=new Pig();
                    break;
                default:
                    pet=new Bird();
            }
           //验证接口  
         Interface.ensureImplement(pet,Pet);//判断pet对象是否全部实现接口Pet里面全部的方法    (对象,接口)
          pet.eat();
          pet.register();
          return pet;

        }
    }
(3)分析宠物的一些特点可以将一些公共的部分提取出来(这里只是简单的提取)

 

   //基类  有共同的提出来
    function basePet() {
        this.register=function () {
            document.write("宠物登记...<br>");
        }
        this.eat=function () {
            document.write("宠物吃饭...<br>");
        }
    }

(4)各个实现类 ---这里是各种动物

   function Dog() {
        Dog.superClass.constructor.call(this);//继承父类
        //实现接口部分
        this.run=function () {
            document.write("小狗跑......<br>")
        }
        this.sing=function () {
            document.write("小狗唱歌......<br>")
        }
    }

    function Cat() {
        Cat.superClass.constructor.call(this);//继承父类
        //实现接口部分
        this.run=function () {
            document.write("小猫跑......<br>")
        }
        this.sing=function () {
            document.write("小猫唱歌......<br>")
        }
    }
    function Pig() {
        Pig.superClass.constructor.call(this);//继承父类
        //实现接口部分
        this.run=function () {
            document.write("小猪跑......<br>")
        }
        this.sing=function () {
            document.write("小猪唱歌......<br>")
        }
    }
    function Bird() {
        Bird.superClass.constructor.call(this);//继承父类
        //实现接口部分
        this.run=function () {
            document.write("小鸟跑......<br>")
        }
        this.sing=function () {
            document.write("小鸟唱歌......<br>")
        }
    }

(5)各个实现类继承基类

//继承
extend(Dog,basePet); extend(Cat,basePet); extend(Pig,basePet); extend(Bird,basePet);

(6)创建宠物的开始卖宠物

var newPetShop=new PetShop();
   var flowerPig=newPetShop.sellPet("pig");
    flowerPig.run();

结果为:

总结一下,上述好像没怎么体现有关工厂之类的,我们应该注意到这么一个问题就是:当需要增加一个新品种宠物时,我们需要修改 \'宠物店类\',耦合度较高。

为了解决这个问题我们使用简单工厂模式来解决。

 

 

2,简单工厂模式(针对上述的改进)

(1)接口文件与继承文件的的引入  同上面

(2)静态工厂

//使用工厂方式创建宠物对象 
// 静态工厂
    var factoryPet={
        //出售宠物的方法
        getPet:function (kind) {
            //宠物对象
            var pet;
            //宠物种类
            switch (kind){
                case  \'dog\':
                    pet=new Dog();
                    break;
                case  \'cat\':
                    pet=new Cat();
                    break;
                case  \'pig\':
                    pet=new Pig();
                    break;
                default:
                    pet=new Bird();
            }
            //验证接口
            Interface.ensureImplement(pet,Pet);//判断pet对象是否全部实行接口Pet里面全部的方法
            return pet;
        }
    }

(3)利用工厂创建宠物店对象

 var factoryPetShop=function () {}
    factoryPetShop.prototype={
        getPet:function (kind) {
            var pet=factoryPet.getPet(kind);
            pet.eat();
            pet.register();
            return pet;
        }
    }

(4)从宠物店购买宠物实现

  var newPetShop=new factoryPetShop();
    var flowerCat=newPetShop.getPet("cat");
    flowerCat.sing();

(5)使用简单工厂实现的全部代码(数字标号表示其思考的先后顺序)

(function () {
    //(2)接口调用
    var Pet=new Interface("Pet",["eat","run","sing","register"]);

    //(3)基类  分析后有共同的提出来作为基类
    function basePet() {
        this.register=function () {
            document.write("宠物登记。。。。<br>");
        }
        this.eat=function () {
            document.write("宠物吃饭。。。。<br>");
        }
    }
    //(4)实现类  继承基类+接口实现
    function Dog() {
        Dog.superClass.constructor.call(this);//继承父类
        //实现接口
        this.run=function () {
            document.write("小狗跑......<br>")
        }
        this.sing=function () {
            document.write("小狗唱歌......<br>")
        }
    }
    function Cat() {
        Cat.superClass.constructor.call(this);//继承父类
        //实现接口
        this.run=function () {
            document.write("小猫跑......<br>")
        }
        this.sing=function () {
            document.write("小猫唱歌......<br>")
        }
    }
    function Pig() {
        Pig.superClass.constructor.call(this);//继承父类
        //实现接口
        this.run=function () {
            document.write("小猪跑......<br>")
        }
        this.sing=function () {
            document.write("小猪唱歌......<br>")
        }
    }
    function Bird() {
        Bird.superClass.constructor.call(this);//继承父类
        //实现接口
        this.run=function () {
            document.write("小鸟跑......<br>")
        }
        this.sing=function () {
            document.write("小鸟唱歌......<br>")
        }
    }
   //继承
    extend(Dog,basePet);
    extend(Cat,basePet);
    extend(Pig,basePet);
    extend(Bird,basePet);


   //(1)使用工厂方式创建宠物对象
   // 静态工厂
    var factoryPet={
        //出售宠物的方法
        getPet:function (kind) {
            //宠物对象
            var pet;
            //宠物种类
            switch (kind){
                case  \'dog\':
                    pet=new Dog();
                    break;
                case  \'cat\':
                    pet=new Cat();
                    break;
                case  \'pig\':
                    pet=new Pig();
                    break;
                default:
                    pet=new Bird();
            }
            //验证接口
            Interface.ensureImplement(pet,Pet);//判断pet对象是否全部实行接口Pet里面全部的方法
            return pet;
        }
    }
    //(5)利用工厂的宠物店对象(宠物店买宠物)
    var factoryPetShop=function () {}
    factoryPetShop.prototype={
        getPet:function (kind) {
            var pet=factoryPet.getPet(kind);
            pet.eat();
            pet.register();
            return pet;
        }
    }
//(6)从宠物店购买宠物
    var newPetShop=new factoryPetShop();//宠物工厂
    var flowerCat=newPetShop.getPet("cat");//从宠物工厂中得到宠物
    flowerCat.sing();

})()

总结一下,上述看似完美,但是任有问题存在:比如说:张三的宠物店想卖哈士奇,李四的宠物店想卖鸟时,这样的话,宠物都是通过一个工厂生产的,并不一定满足各个卖家的需求。

所以我们需要根据各个厂家的需求,有不同的工厂,各个卖家可以根据自己需求使用不同的工厂(其实是利用不同子类实现各自合适的工厂),用于满足每个宠物店的不同。

于是我们有了复杂的工厂用来解决该问题。

 

3,复杂工厂:通过把实例化的任务交给子类来完成的,用以到达松耦合的目的。

此处同样是根据上述进行改进的,还是简单的说明一下实现过程

(1)在html中将接口文件的引进,代码为

//定义一个静态方法来实现接口与实现类的直接检验
//静态方法不要写出Interface.prototype ,因为这是写到接口的原型链上的
//我们要把静态的函数直接写到类层次上
//定义一个接口类
var Interface=function (name,methods) {//name:接口名字
    if(arguments.length<2){
        alert("必须是两个参数")
    }
    this.name=name;
    this.methods=[];//定义一个空数组装载函数名
    for(var i=0;i<methods.length;i++){
        if(typeof  methods[i]!="string"){
            alert("函数名必须是字符串类型");
        }else {
            this.methods.push( methods[i]);
        }
    }
};
Interface.ensureImplement=function (object) {
    if(arguments.length<2){
        throw  new Error("参数必须不少于2个")
        return false;
    }
    for(var i=1;i<arguments.length;i++){
        var inter=arguments[i];
        //如果是接口就必须是Interface类型
        if(inter.constructor!=Interface){
            throw  new Error("如果是接口类的话,就必须是Interface类型");
        }
        //判断接口中的方法是否全部实现
        //遍历函数集合
        for(var j=0;j<inter.methods.length;j++){
            var method=inter.methods[j];//接口中所有函数

            //object[method]传入的函数
            //最终是判断传入的函数是否与接口中所用函数匹配
            if(!object[method]||typeof object[method]!="function" ){//实现类中必须有方法名字与接口中所用方法名相同
                throw  new Error("实现类中没有完全实现接口中的所有方法")
            }
        }
    }
}

(2)在html中将继承文件引入,代码如下,

/*创建extend函数为了程序中所有的继承操作*/
//subClass:子类  superClass:超类
function extend(subClass,superClass) {
    //1,使子类原型属性等于父类的原型属性

    //初始化一个中间空对象,目的是为了转换主父关系
    var F = function () {};
    F.prototype = superClass.prototype;
    //2, 让子类继承F
    subClass.prototype = new F();
    subClass.prototype.constructor = subClass;
    //3,为子类增加属性 superClass ==》原型链的引用
    subClass.superClass = superClass.prototype;
    //4,增加一个保险,就算你的原型类是超类(Object)那么也要把你的构造函数级别降下来
    if (superClass.prototype.constructor == Object.prototype.constructor) {
        superClass.prototype.constructor = superClass;
    }
}

(3)分析各个类提出相同的部分作为基类,基类代码如下

//基类  分析后有共同的提出来作为基类
    function basePet() {
        this.register=function () {
            document.write("宠物登记。。。。<br>");
        };
        this.eat=function () {
            document.write("宠物吃饭。。。。<br>");
        }
    }

(4)各个具体的实现类:继承基类+接口实现

//各个宠物类(实现类)  继承基类+接口实现
    function Dog() {
        Dog.superClass.constructor.call(this);//继承父类
        //实现接口
        this.run=function () {
            document.write("小狗跑......<br>")
        }
        this.sing=function () {
            document.write("小狗唱歌......<br>")
        }
    }
    function Cat() {
        Cat.superClass.constructor.call(this);//继承父类
        //实现接口
        this.run=function () {
            document.write("小猫跑......<br>")
        }
        this.sing=function () {
            document.write("小猫唱歌......<br>")
        }
    }
    function Pig() {
        Pig.superClass.constructor.call(this);//继承父类
        //实现接口
        this.run=function () {
            document.write("小猪跑......<br>")
        }
        this.sing=function () {
            document.write("小猪唱歌......<br>")
        }
    }
    function Bird() {
        Bird.superClass.constructor.call(this);//继承父类
        //实现接口
        this.run=function () {
            document.write("小鸟跑......<br>")
        };
        this.sing=function () {
            document.write("小鸟唱歌......<br>")
        }
    }

(5)实现类与基类的继承实现,代码如下(调用extend())

extend(Dog,basePet);//动物狗继承基类
    extend(Cat,basePet);
    extend(Pig,basePet);
    extend(Bird,basePet);

(6)将商店抽取出来,做成抽象类,代码如下

//把核心商店抽取出来
    var petShop=function () {};
       petShop.prototype={//模拟抽象类  需要被子类覆盖
           getPet:function (kind){
               var pet=this.getpet(kind);
               pet.eat();
               pet.register();
               return pet;
           },
           getpet:function (model){
             throw  new Error("该类是抽象类,不能实例化")

           }
       };

(7)利用子类来满足各个商家的不同类型宠物店的实现 ,代码如下

//利用子类来满足之前的需求(多态)
    var oneShop=function () { }
       extend(oneShop,petShop);//继承
        //覆写方法
      oneShop.prototype.getpet=function (model) {
          //宠物对象
          var pet;
          //宠物种类
          switch (model){
              case  \'dog\':
                  pet=new Dog();
                  break;
              default:
                  pet=new Bird();
          }
          //验证接口
          Interface.ensureImplement(pet,Pet);//判断pet对象是否全部实行接口Pet里面全部的方法
          pet.eat();
          pet.register();
          return pet;
      };

同上,这个也是一个不同的子类

 twoShop=function () {};
    extend(twoShop,petShop);//商店的继承
    //覆写方法
      twoShop.prototype.getPet=function (model) {
          //宠物对象
          var pet;
          //宠物种类
          switch (kind){
              case  \'pig\':
                  pet=new Pig();
                  break;
              default:
                  pet=new Bird();
          }
          //验证接口
          Interface.ensureImplement(pet,Pet);//判断pet对象是否全部实行接口Pet里面全部的方法
          pet.eat();
          pet.register();
          return pet;
      };

(8) 使用,实质是子类对父类的实例化

这里实现其中一个宠物店,另外一个同理。

//子类对父类的实例化
    var jim=new oneShop();
     var pig= jim.getpet("dog");
        pig.run();
        pig.sing()

(9)上述代码综合在一起为,代码如下

(function () {
    //(2)接口调用
    var Pet=new Interface("Pet",["eat","run","sing","register"]);

    //(1)基类  分析后有共同的提出来作为基类
    function basePet() {
        this.register=function () {
            document.write("宠物登记。。。。<br>");
        };
        this.eat=function () {
            document.write("宠物吃饭。。。。<br>");
        }
    }
    //(3)实现类  继承基类+接口实现
    function Dog() {
        Dog.superClass.constructor.call(this);//继承父类
        //实现接口
        this.run=function () {
            document.write("小狗跑......<br>")
        }
        this.sing=function () {
            document.write("小狗唱歌......<br>")
        }
    }
    function Cat() {
        Cat.superClass.constructor.call(this);//继承父类
        //实现接口
        this.run=function () {
            document.write("

以上是关于JavaScript设计模式--简单工厂模式的主要内容,如果未能解决你的问题,请参考以下文章

代码片-策略模式+工厂模式

代码片-策略模式+工厂模式

设计模式-工厂模式(JavaScript)

Javascript设计模式第二课 神奇的魔术师——简单工厂模式

javascript设计模式-工厂模式(简单工厂)

《JavaScript设计模式 张》整理