javaScript设计模式系列(四) 工厂模式

原创
2017/07/07 11:03
阅读数 6

前言

工厂这个名词我们可以先分析一下,一般工厂的特点都是大批量的造东西,要是只做一个的话,倒是可以在家搭个小作坊,半年产值一个也是可以的。再有呢,工厂普遍是单一生产,哪怕是产品功能改了,那我就把流水线改一改,换几个机组,大的流程还是不变的。那如果要是,工厂今天造船,明天想造飞机,基本是没戏,造飞机和造船是完全不同的两套流程和设备,这么大的变动,不是一个工厂想改就改的。

正文:

现在正好有一个店家在卖手机,他们自己做手机自己销售,这店家就叫DayDayPhone,买手机的时候呢你告诉他一个牌子,就能买到这个牌子的手机了:

var DayDayPhone = {
  sellPhone:function(brand){
    var Phone;
    switch (brand){
      case 'Apple':
      Phone = new ApplePhone();
      break;
      case 'Huawei':
      Phone = new HuaweiPhone();
      break;
      default 'Xiaomi':
      Phone = new XiaomiPhone();
      break;
    }
    return Phone;
  }
}
function ApplePhone(){};
function HuaweiPhone(){};
function XiaomiPhone(){};
var havePhone = DayDayPhone.sellPhone('Huawei');

这样的销售未免太单调了,所以厂家给了一次抽奖的机会,会帮你开机测试一下,只是区别是抽奖是店家的方法,开机测试呢是手机自带的功能。看起来就是这样:

var DayDayPhone = {
  lottery:function (){
    console.log('您已经使用了一次抽奖机会');
  },
  sellPhone:function(brand){
    var Phone;
    switch (brand){
      case 'Apple':
      Phone = new ApplePhone();
      break;
      case 'Huawei':
      Phone = new HuaweiPhone();
      break;
      default:
      Phone = new XiaomiPhone();
      break;
    }
    this.lottery();
    Phone.starting();
    return Phone;
  }
}
function ApplePhone(){
  this.starting = function(){};
  //其他方法
};
function HuaweiPhone(){
  this.starting = function(){};
  //其他方法
};
function XiaomiPhone(){
  this.starting = function(){};
  //其他方法
};
var havePhone = DayDayPhone.sellPhone('Huawei');

现在看起来一切还好啊,什么工厂什么的,提那些干什么。只是有一天店里可以卖Vivo手机了,于是店长发现了一个问题,我卖手机的流程一点没变,抽个奖,测试一下,手机就是你的了。但是一来新手机店里就要大改,主要就是生产手机的这块,能不能给它交给一个工厂,我拿到货就卖,你们工厂呢来了品牌,无非是改改流水线,很好管理。于是现在的模式就是这样了:

var DayDayPhone = {
  lottery:function (){
    console.log('您已经使用了一次抽奖机会');
  },
  sellPhone:function(){
    var Phone = PhoneFactory.madePhone('Vivo');
    this.lottery();
    Phone.starting();
    return Phone;
  }
}
var PhoneFactory = {
  madePhone:function(brand){
    var FactoryPhone;
    switch (brand){
      case 'Apple':
      FactoryPhone = new ApplePhone();
      break;
      case 'Huawei':
      FactoryPhone = new HuaweiPhone();
      break;
      case 'Vivo':
      FactoryPhone = new VivoPhone();
      break;
      default:
      FactoryPhone = new XiaomiPhone();
      break;
    }
    return FactoryPhone;
  }
}
function VivoPhone(){
  this.starting = function(){};
  this.notice = function(){
    console.log('我新买的Vivo手机');
  }
  //其他方法
};
function ApplePhone(){
  this.starting = function(){};
  //其他方法
};
function HuaweiPhone(){
  this.starting = function(){};
  //其他方法
};
function XiaomiPhone(){
  this.starting = function(){};
  //其他方法
};
var havePhone = DayDayPhone.sellPhone('Huawei');
havePhone.notice();//我新买的Vivo手机

现在我们稍稍改动一下,如果像现在这样,那这就是我一个人的店,要是能用一个方法,给不同的人开店该多好,我只要给我的点起个名字,用一下开店的方法,那我的店就建成了。实际上就是把上面的代码,改写成构造函数的形式:

function PhoneShop() {};
PhoneShop.prototype.lottery = function() {
  console.log('您已经使用了一次抽奖机会');
};
PhoneShop.prototype.sellPhone = function(brand) {
  var Phone = PhoneFactory.madePhone(brand);
  this.lottery();
  Phone.starting();
  return Phone;
}
//以下的代码都没变
var PhoneFactory = {
  madePhone: function(brand) {
    var FactoryPhone;
    switch(brand) {
      case 'Apple':
        FactoryPhone = new ApplePhone();
        break;
      case 'Huawei':
        FactoryPhone = new HuaweiPhone();
        break;
      case 'Vivo':
        FactoryPhone = new VivoPhone();
        break;
      default:
        FactoryPhone = new XiaomiPhone();
        break;
    }
    return FactoryPhone;
  }
}

function VivoPhone() {
  this.starting = function() {};
  this.notice = function() {
    console.log('我新买的Vivo手机');
  }
  //其他方法
};

function ApplePhone() {
  this.starting = function() {};
  //其他方法
};

function HuaweiPhone() {
  this.starting = function() {};
  //其他方法
};

function XiaomiPhone() {
  this.starting = function() {};
  //其他方法
};
var DayDayPhone = new PhoneShop();
var havePhone = DayDayPhone.sellPhone('Huawei');
havePhone.notice(); //我新买的Vivo手机

这样我们其实就完成了一个简单工厂。那工厂模式具体怎么表述呢,我们一会再说,首要目的是先感受一下什么是工厂模式。

上面的代码还是有点不完美,那真正的工厂模式应该是什么样的。我们继续说店长家的故事。虽然工厂被分出去了,看起来很不错很好管理。但是店长觉得这样不行,这工厂原来就是我的,现在分出去了好像跟我一点关系都没有了,而且如果以后要是开始卖平板电脑Ipad,那就是再开了一家工厂。如果像现在这样操作并不是很方便,卖东西的时候要判断顾客买的是平板还是手机:

function PhoneOrIpadShop() {};
PhoneOrIpadShop.prototype.lottery = function() {
  console.log('您已经使用了一次抽奖机会');
};
//传入两个参数第一个判断是手机还是平板电脑,第二个是品牌
PhoneOrIpadShop.prototype.sellPhoneOrIpad = function(kind,brand) {
  var product;
  if(kind === 'Phone'){
     product = PhoneFactory.madePhone(brand);
  }else if(kind === 'Ipad'){
     product = IpadFactory.madeIpad(brand);
  }
  this.lottery();
  product.starting();
  return product;
}
var PhoneFactory = {
  madePhone: function(brand) {
    var FactoryPhone;
    switch(brand) {
      case 'Apple':
        FactoryPhone = new ApplePhone();
        break;
      case 'Huawei':
        FactoryPhone = new HuaweiPhone();
        break;
      case 'Vivo':
        FactoryPhone = new VivoPhone();
        break;
      default:
        FactoryPhone = new XiaomiPhone();
        break;
    }
    return FactoryPhone;
  }
}
var IpadFactory = {
  madeIpad: function(brand) {
    var FactoryIpad;
    switch(brand) {
      case 'Apple':
        FactoryIpad = new AppleIpad();
        break;
      case 'Huawei':
        FactoryIpad = new HuaweiIpad();
        break;
      default:
        FactoryIpad = new XiaomiIpad();
        break;
    }
    return FactoryIpad;
  }
}
//手机
function VivoPhone() {
  this.starting = function() {};
  this.notice = function() {
    console.log('我新买的Vivo手机');
  }
};
function ApplePhone() {this.starting = function() {};};
function HuaweiPhone() {this.starting = function() {};};
function XiaomiPhone() {this.starting = function() {};};
//平板电脑
function AppleIpad() {
  this.starting = function() {};
  this.notice = function() {console.log('新买的苹果平板')};
};
function HuaweiIpad() {this.starting = function() {};};
function XiaomiIpad() {};

var DayDayPhone = new PhoneOrIpadShop();
var havePhone = DayDayPhone.sellPhoneOrIpad("Ipad",'Apple');
havePhone.notice(); //新买的苹果平板

店长愁的一夜白了头,这是一夜回到解放前的节奏啊,本来管理的好好的,结果又像刚开始开店的时候了,要是开始卖自行车了又要大改了,开店的方法(构造函数),要添加种类的判断。我们可不可以通过工厂建造店铺(实例化),这样就可已卖单一商品了,原来的判断就不需要了。也就是把现在的工厂的对象改为构造函数。

那原来的那些活动怎么办,我们就一起拿过来,这就用到了继承。从店长家的店里继承过来,这时候店长家的店就好多了,不需要做哪些判断了,也不用用来作为开店的构造函数来用了,这部分的代码是这样的

继承的方法请看 《javaScript设计模式系列(五) 继承》。。。。 但是我还没有写,先记住一个关键字extend,用法是extend(子类,父类),这样就从继承来了父类原型的方法。

var PhoneFactory = function() {};
//继承父级的方法
extend(PhoneFactory, BaseShop);
PhoneFactory.prototype.madeProduct = function(brand) {
  var Phone;
  switch(brand) {
    case 'Apple':
      Phone = new ApplePhone();
      break;
    case 'Huawei':
      Phone = new HuaweiPhone();
      break;
    case 'Vivo':
      Phone = new VivoPhone();
      break;
    default:
      Phone = new XiaomiPhone();
      break;
  }
  return FactoryPhone;
}
var IpadFactory = function() {};
//继承父级的方法
extend(IpadFactory, BaseShop);
IpadFactory.prototype.madeProduct = function(brand) {
  var Ipad;
  switch(brand) {
    case 'Apple':
      Ipad = new AppleIpad();
      break;
    case 'Huawei':
      Ipad = new HuaweiIpad();
      break;
    default:
      Ipad = new XiaomiIpad();
      break;
  }
  return Ipad;
}

那原来的店已经不需要用来实例化新店了,以前造电子啊产品的方法已经不能用了,怎么告诉别人呢?如果要调用店里制造商品的方法就报一个错误,告诉别人这个方法不能用,应为现在开店是用工厂开了。

function BaseShop() {};
BaseShop.prototype.lottery = function() {
  console.log('您已经使用了一次抽奖机会');
};
BaseShop.prototype.gift = function() {
  console.log('你获得了一些赠品');
};
BaseShop.prototype.sellProduct = function(brand) {
  this.lottery();
  this.gift();
  var Product = this.madeProduct(brand);
  Product.starting();
  return Product;
};
BaseShop.prototype.madeProduct = function() {
  console.log('madeProduct方法不能被使用,因为BaseShop是一个抽象类,不能实例化,只能派生子类');
}

sellProduct 方法不能被使用,它又会被继承到工厂里面怎么办,其实我们已经解决了,在工厂中的代码我们重写了sellProduct方法,覆盖了父级的方法。工厂是挂载基础店下的感觉,又有了基础店的方法。全部的代码就像下面:

function BaseShop() {};
BaseShop.prototype.lottery = function() {
  console.log('您已经使用了一次抽奖机会');
};
BaseShop.prototype.gift = function() {
  console.log('你获得了一些赠品');
};
BaseShop.prototype.sellProduct = function(brand) {
  this.lottery();
  this.gift();
  var Product = this.madeProduct(brand);
  Product.starting();
  return Product;
};
BaseShop.prototype.madeProduct = function() {
  console.log('madeProduct方法不能被使用,因为BaseShop是一个抽象类,不能实例化,只能派生子类');
}

var PhoneFactory = function() {};
//继承父级的方法
extend(PhoneFactory, BaseShop);
PhoneFactory.prototype.madeProduct = function(brand) {
  var Phone;
  switch(brand) {
    case 'Apple':
  Phone = new ApplePhone();
  break;
case 'Huawei':
  Phone = new HuaweiPhone();
  break;
case 'Vivo':
      Phone = new VivoPhone();
      break;
    default:
      Phone = new XiaomiPhone();
      break;
  }
  Interface.ensureImplements(Phone,PhoneInterface);
  return Phone;
}
var IpadFactory = function() {};
//继承父级的方法
extend(IpadFactory, BaseShop);
IpadFactory.prototype.madeProduct = function(brand) {
  var Ipad;
  switch(brand) {
    case 'Apple':
  Ipad = new AppleIpad();
  break;
case 'Huawei':
      Ipad = new HuaweiIpad();
      break;
    default:
      Ipad = new XiaomiIpad();
      break;
  }
  Interface.ensureImplements(Ipad,IpadInterface);
  return Ipad;
}
//手机
var PhoneInterface = new Interface('PhoneInterface',['starting','notice']);
function VivoPhone() {
  this.starting = function() {};
  this.notice = function() {
    console.log('我新买的Vivo手机');
  }
};

function ApplePhone() {
  this.starting = function() {};
};

function HuaweiPhone() {
  this.starting = function() {};
};

function XiaomiPhone() {
  this.starting = function() {};
};
//平板电脑
var IpadInterface = new Interface('IpadInterface',['starting','notice']);
function AppleIpad() {
  this.starting = function() {};
  this.notice = function() {
    console.log('新买的苹果平板')
  };
};

function HuaweiIpad() {
  this.starting = function() {};
};

function XiaomiIpad() {
  this.starting = function() {};
};

var DayDayPhone = new IpadFactory();
var havePhone = DayDayPhone.sellProduct('Apple');
havePhone.notice(); //新买的苹果平板

总结一下,工厂模式可一实现松耦合,把公用的代码集中在一个地方,个体的代码写在子类中,这样如果需要较多的子类去组成一个较大的对象是很好管理的。

展开阅读全文
打赏
1
1 收藏
分享
加载中
更多评论
打赏
0 评论
1 收藏
1
分享
返回顶部
顶部