国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

從ES6重新認(rèn)識(shí)JavaScript設(shè)計(jì)模式(二): 工廠模式

Reducto / 1809人閱讀

摘要:簡(jiǎn)單工廠模式簡(jiǎn)單工廠模式又叫靜態(tài)工廠模式,由一個(gè)工廠對(duì)象決定創(chuàng)建某一種產(chǎn)品對(duì)象類的實(shí)例。工廠方法模式工廠方法模式的本意是將實(shí)際創(chuàng)建對(duì)象的工作推遲到子類中,這樣核心類就變成了抽象類。抽象工廠模式一般用在

1 什么是工廠模式?

工廠模式是用來(lái)創(chuàng)建對(duì)象的一種最常用的設(shè)計(jì)模式。我們不暴露創(chuàng)建對(duì)象的具體邏輯,而是將將邏輯封裝在一個(gè)函數(shù)中,那么這個(gè)函數(shù)就可以被視為一個(gè)工廠。工廠模式根據(jù)抽象程度的不同可以分為:簡(jiǎn)單工廠,工廠方法和抽象工廠。

如果只接觸過(guò)JavaScript這門(mén)語(yǔ)言的的人可能會(huì)對(duì)抽象這個(gè)詞的概念有點(diǎn)模糊,因?yàn)镴avaScript一直將abstract作為保留字而沒(méi)有去實(shí)現(xiàn)它。如果不能很好的理解抽象的概念,那么就很難理解工廠模式中的三種方法的異同。所以,我們先以一個(gè)場(chǎng)景去簡(jiǎn)單的講述一下抽象和工廠的概念。

想象一下你的女朋友生日要到了,你想知道她想要什么,于是你問(wèn)她:“親愛(ài)的,生日要到了你想要什么生日禮物啊?”

正巧你女朋友是個(gè)貓奴,最經(jīng)迷上了抖音上的一只超級(jí)可愛(ài)的蘇格蘭折耳貓,她也很想要一只網(wǎng)紅同款貓。

于是她回答你說(shuō):“親愛(ài)的,我想要一只動(dòng)物。”

你心平氣和的問(wèn)她:“想要什么動(dòng)物啊?”

你女友說(shuō):“我想要貓科動(dòng)物。”

這時(shí)你內(nèi)心就納悶了,貓科動(dòng)物有老虎,獅子,豹子,猞猁,還有各種小貓,我哪里知道你要什么?

于是你問(wèn)女友:“你要哪種貓科動(dòng)物啊?”

“笨死了,還要哪種,肯定是小貓咪啊,難道我們家還能像迪拜土豪那樣養(yǎng)老虎啊!”你女朋友答道。

“好好, 那你想要哪個(gè)品種的貓呢?”你問(wèn)道

“我想要外國(guó)的品種, 不要中國(guó)的土貓” 你女友傲嬌的回答到。

這時(shí)你已經(jīng)快奔潰了,作為程序員的你再也受不了這種擠牙膏式的提問(wèn),于是你哀求到:“親愛(ài)的,你就直接告訴我你到底想要哪個(gè)品種,哪個(gè)顏色,多大的貓?”

你女友想了想抖音的那只貓,回答道:“我想要一只灰色的,不超過(guò)1歲的蘇格蘭短耳貓!”

于是,你在女友生日當(dāng)天到全國(guó)最大的寵物批發(fā)市場(chǎng)里面去,挑了一只“灰色的,不超過(guò)1歲的蘇格蘭短耳貓”回家送給了你女友, 圓了你女友擁有網(wǎng)紅同款貓的夢(mèng)想!

上面中你最終買到并送給女友那只貓可以被看作是一個(gè)實(shí)例對(duì)象寵物批發(fā)市場(chǎng)可以看作是一個(gè)工廠,我們可以認(rèn)為它是一個(gè)函數(shù),這個(gè)工廠函數(shù)里面有著各種各樣的動(dòng)物,那么你是如何獲取到實(shí)例的呢?因?yàn)槟憬o寵物批發(fā)市場(chǎng)傳遞了正確的參數(shù), “color: 灰色”“age: 不超過(guò)1歲”"breed:蘇格蘭短耳",**“category:
貓"。前面的對(duì)話中, 你女朋友回答“動(dòng)物”,“貓科動(dòng)物”,“國(guó)外的品種”讓你不明白她到底想要什么,就是因?yàn)樗f(shuō)得太抽象了。她回答的是一大類動(dòng)物的共有特征而不是具體動(dòng)物,這種將復(fù)雜事物的一個(gè)或多個(gè)共有特征抽取出來(lái)的思維過(guò)程就是抽象**。

既然已經(jīng)明白了抽象的概念,下面我們來(lái)看一下之前提到的工廠模式的三種實(shí)現(xiàn)方法: 簡(jiǎn)單工廠模式、工廠方法模式、抽象工廠模式。

1.1 簡(jiǎn)單工廠模式

簡(jiǎn)單工廠模式又叫靜態(tài)工廠模式,由一個(gè)工廠對(duì)象決定創(chuàng)建某一種產(chǎn)品對(duì)象類的實(shí)例。主要用來(lái)創(chuàng)建同一類對(duì)象。

在實(shí)際的項(xiàng)目中,我們常常需要根據(jù)用戶的權(quán)限來(lái)渲染不同的頁(yè)面,高級(jí)權(quán)限的用戶所擁有的頁(yè)面有些是無(wú)法被低級(jí)權(quán)限的用戶所查看。所以我們可以在不同權(quán)限等級(jí)用戶的構(gòu)造函數(shù)中,保存該用戶能夠看到的頁(yè)面。在根據(jù)權(quán)限實(shí)例化用戶。代碼如下:

let UserFactory = function (role) {
  function SuperAdmin() {
    this.name = "超級(jí)管理員",
    this.viewPage = ["首頁(yè)", "通訊錄", "發(fā)現(xiàn)頁(yè)", "應(yīng)用數(shù)據(jù)", "權(quán)限管理"]
  }
  function Admin() {
    this.name = "管理員",
    this.viewPage = ["首頁(yè)", "通訊錄", "發(fā)現(xiàn)頁(yè)", "應(yīng)用數(shù)據(jù)"]
  }
  function NormalUser() {
    this.name = "普通用戶",
    this.viewPage = ["首頁(yè)", "通訊錄", "發(fā)現(xiàn)頁(yè)"]
  }

  switch (role) {
    case "superAdmin":
      return new SuperAdmin();
      break;
    case "admin":
      return new Admin();
      break;
    case "user":
      return new NormalUser();
      break;
    default:
      throw new Error("參數(shù)錯(cuò)誤, 可選參數(shù):superAdmin、admin、user");
  }
}

//調(diào)用
let superAdmin = UserFactory("superAdmin");
let admin = UserFactory("admin") 
let normalUser = UserFactory("user")

UserFactory就是一個(gè)簡(jiǎn)單工廠,在該函數(shù)中有3個(gè)構(gòu)造函數(shù)分別對(duì)應(yīng)不同的權(quán)限的用戶。當(dāng)我們調(diào)用工廠函數(shù)時(shí),只需要傳遞superAdmin, admin, user這三個(gè)可選參數(shù)中的一個(gè)獲取對(duì)應(yīng)的實(shí)例對(duì)象。你也許發(fā)現(xiàn),我們的這三類用戶的構(gòu)造函數(shù)內(nèi)部很相識(shí),我們還可以對(duì)其進(jìn)行優(yōu)化。

let UserFactory = function (role) {
  function User(opt) {
    this.name = opt.name;
    this.viewPage = opt.viewPage;
  }

  switch (role) {
    case "superAdmin":
      return new User({ name: "超級(jí)管理員", viewPage: ["首頁(yè)", "通訊錄", "發(fā)現(xiàn)頁(yè)", "應(yīng)用數(shù)據(jù)", "權(quán)限管理"] });
      break;
    case "admin":
      return new User({ name: "管理員", viewPage: ["首頁(yè)", "通訊錄", "發(fā)現(xiàn)頁(yè)", "應(yīng)用數(shù)據(jù)"] });
      break;
    case "user":
      return new User({ name: "普通用戶", viewPage: ["首頁(yè)", "通訊錄", "發(fā)現(xiàn)頁(yè)"] });
      break;
    default:
      throw new Error("參數(shù)錯(cuò)誤, 可選參數(shù):superAdmin、admin、user")
  }
}

//調(diào)用
let superAdmin = UserFactory("superAdmin");
let admin = UserFactory("admin") 
let normalUser = UserFactory("user")

簡(jiǎn)單工廠的優(yōu)點(diǎn)在于,你只需要一個(gè)正確的參數(shù),就可以獲取到你所需要的對(duì)象,而無(wú)需知道其創(chuàng)建的具體細(xì)節(jié)。但是在函數(shù)內(nèi)包含了所有對(duì)象的創(chuàng)建邏輯(構(gòu)造函數(shù))和判斷邏輯的代碼,每增加新的構(gòu)造函數(shù)還需要修改判斷邏輯代碼。當(dāng)我們的對(duì)象不是上面的3個(gè)而是30個(gè)或更多時(shí),這個(gè)函數(shù)會(huì)成為一個(gè)龐大的超級(jí)函數(shù),便得難以維護(hù)。所以,簡(jiǎn)單工廠只能作用于創(chuàng)建的對(duì)象數(shù)量較少,對(duì)象的創(chuàng)建邏輯不復(fù)雜時(shí)使用

1.2 工廠方法模式

工廠方法模式的本意是將實(shí)際創(chuàng)建對(duì)象的工作推遲到子類中,這樣核心類就變成了抽象類。但是在JavaScript中很難像傳統(tǒng)面向?qū)ο竽菢尤?shí)現(xiàn)創(chuàng)建抽象類。所以在JavaScript中我們只需要參考它的核心思想即可。我們可以將工廠方法看作是一個(gè)實(shí)例化對(duì)象的工廠類。

在簡(jiǎn)單工廠模式中,我們每添加一個(gè)構(gòu)造函數(shù)需要修改兩處代碼。現(xiàn)在我們使用工廠方法模式改造上面的代碼,剛才提到,工廠方法我們只把它看作是一個(gè)實(shí)例化對(duì)象的工廠,它只做實(shí)例化對(duì)象這一件事情! 我們采用安全模式創(chuàng)建對(duì)象。

//安全模式創(chuàng)建的工廠方法函數(shù)
let UserFactory = function(role) {
  if(this instanceof UserFactory) {
    var s = new this[role]();
    return s;
  } else {
    return new UserFactory(role);
  }
}

//工廠方法函數(shù)的原型中設(shè)置所有對(duì)象的構(gòu)造函數(shù)
UserFactory.prototype = {
  SuperAdmin: function() {
    this.name = "超級(jí)管理員",
    this.viewPage = ["首頁(yè)", "通訊錄", "發(fā)現(xiàn)頁(yè)", "應(yīng)用數(shù)據(jù)", "權(quán)限管理"]
  },
  Admin: function() {
    this.name = "管理員",
    this.viewPage = ["首頁(yè)", "通訊錄", "發(fā)現(xiàn)頁(yè)", "應(yīng)用數(shù)據(jù)"]
  },
  NormalUser: function() {
    this.name = "普通用戶",
    this.viewPage = ["首頁(yè)", "通訊錄", "發(fā)現(xiàn)頁(yè)"]
  }
}

//調(diào)用
let superAdmin = UserFactory("SuperAdmin");
let admin = UserFactory("Admin") 
let normalUser = UserFactory("NormalUser")

上面的這段代碼就很好的解決了每添加一個(gè)構(gòu)造函數(shù)就需要修改兩處代碼的問(wèn)題,如果我們需要添加新的角色,只需要在UserFactory.prototype中添加。例如,我們需要添加一個(gè)VipUser:

UserFactory.prototype = {
  //....
  VipUser: function() {
    this.name = "付費(fèi)用戶",    
    this.viewPage = ["首頁(yè)", "通訊錄", "發(fā)現(xiàn)頁(yè)", "VIP頁(yè)"]
  }
}

//調(diào)用
let vipUser = UserFactory("VipUser");

上面的這段代碼中,使用到的安全模式可能很難一次就能理解。

let UserFactory = function(role) {
  if(this instanceof UserFactory) {
    var s = new this[role]();
    return s;
  } else {
    return new UserFactory(role);
  }
}

因?yàn)槲覀儗?b>SuperAdmin、AdminNormalUser等構(gòu)造函數(shù)保存到了UserFactory.prototype中,也就意味著我們必須實(shí)例化UserFactory函數(shù)才能夠進(jìn)行以上對(duì)象的實(shí)例化。如下面代碼所示

let UserFactory = function() {}

UserFactory.prototype = {
 //...
}

//調(diào)用
let factory = new UserFactory();
let superAdmin = new factory.SuperAdmin();

在上面的調(diào)用函數(shù)的過(guò)程中, 一旦我們?cè)谌魏坞A段忘記使用new, 那么就無(wú)法正確獲取到superAdmin這個(gè)對(duì)象。但是一旦使用安全模式去進(jìn)行實(shí)例化,就能很好解決上面的問(wèn)題。

1.3 抽象工廠模式

上面介紹了簡(jiǎn)單工廠模式和工廠方法模式都是直接生成實(shí)例,但是抽象工廠模式不同,抽象工廠模式并不直接生成實(shí)例, 而是用于對(duì)產(chǎn)品類簇的創(chuàng)建。

上面例子中的superAdminadminuser三種用戶角色,其中user可能是使用不同的社交媒體賬戶進(jìn)行注冊(cè)的,例如:wechatqqweibo。那么這三類社交媒體賬戶就是對(duì)應(yīng)的類簇。在抽象工廠中,類簇一般用父類定義,并在父類中定義一些抽象方法,再通過(guò)抽象工廠讓子類繼承父類。所以,抽象工廠其實(shí)是實(shí)現(xiàn)子類繼承父類的方法

上面提到的抽象方法是指聲明但不能使用的方法。在其他傳統(tǒng)面向?qū)ο蟮恼Z(yǔ)言中常用abstract進(jìn)行聲明,但是在JavaScript中,abstract是屬于保留字,但是我們可以通過(guò)在類的方法中拋出錯(cuò)誤來(lái)模擬抽象類。

let WechatUser = function() {}
WechatUser.prototype = {
  getName: function() {
    return new Error("抽象方法不能調(diào)用");
  }
}

上述代碼中的getPrice就是抽象方法,我們定義它但是卻沒(méi)有去實(shí)現(xiàn)。如果子類繼承WechatUser但是并沒(méi)有去重寫(xiě)getName,那么子類的實(shí)例化對(duì)象就會(huì)調(diào)用父類的getName方法并拋出錯(cuò)誤提示。

下面我們分別來(lái)實(shí)現(xiàn)賬號(hào)管理的抽象工廠方法:

let AccountAbstractFactory = function(subType, superType) {
  //判斷抽象工廠中是否有該抽象類
  if(typeof AccountAbstractFactory[superType] === "function") {
    //緩存類
    function F() {};
    //繼承父類屬性和方法
    F.prototype = new AccountAbstractFactory[superType] ();
    //將子類的constructor指向子類
    subType.constructor = subType;
    //子類原型繼承父類
    subType.prototype = new F();

  } else {
    throw new Error("抽象類不存在!")
  }
}

//微信用戶抽象類
AccountAbstractFactory.WechatUser = function() {
  this.type = "wechat";
}
AccountAbstractFactory.WechatUser.prototype = {
  getName: function() {
    return new Error("抽象方法不能調(diào)用");
  }
}

//qq用戶抽象類
AccountAbstractFactory.QqUser = function() {
  this.type = "qq";
}
AccountAbstractFactory.QqUser.prototype = {
  getName: function() {
    return new Error("抽象方法不能調(diào)用");
  }
}

//新浪微博用戶抽象類
AccountAbstractFactory.WeiboUser = function() {
  this.type = "weibo";
}
AccountAbstractFactory.WeiboUser.prototype = {
  getName: function() {
    return new Error("抽象方法不能調(diào)用");
  }
}

AccountAbstractFactory 就是一個(gè)抽象工廠方法,該方法在參數(shù)中傳遞子類和父類,在方法體內(nèi)部實(shí)現(xiàn)了子類對(duì)父類的繼承。對(duì)抽象工廠方法添加抽象類的方法我們是通過(guò)點(diǎn)語(yǔ)法進(jìn)行添加的。

下面我們來(lái)定義普通用戶的子類:

//普通微信用戶子類
function UserOfWechat(name) {
  this.name = name;
  this.viewPage = ["首頁(yè)", "通訊錄", "發(fā)現(xiàn)頁(yè)"]
}
//抽象工廠實(shí)現(xiàn)WechatUser類的繼承
AccountAbstractFactory(UserOfWechat, "WechatUser");
//子類中重寫(xiě)抽象方法
UserOfWechat.prototype.getName = function() {
  return this.name;
}

//普通qq用戶子類
function UserOfQq(name) {
  this.name = name;
  this.viewPage = ["首頁(yè)", "通訊錄", "發(fā)現(xiàn)頁(yè)"]
}
//抽象工廠實(shí)現(xiàn)QqUser類的繼承
AccountAbstractFactory(UserOfQq, "QqUser");
//子類中重寫(xiě)抽象方法
UserOfQq.prototype.getName = function() {
  return this.name;
}

//普通微博用戶子類
function UserOfWeibo(name) {
  this.name = name;
  this.viewPage = ["首頁(yè)", "通訊錄", "發(fā)現(xiàn)頁(yè)"]
}
//抽象工廠實(shí)現(xiàn)WeiboUser類的繼承
AccountAbstractFactory(UserOfWeibo, "WeiboUser");
//子類中重寫(xiě)抽象方法
UserOfWeibo.prototype.getName = function() {
  return this.name;
}

上述代碼我們分別定義了UserOfWechatUserOfQqUserOfWeibo三種類。這三個(gè)類作為子類通過(guò)抽象工廠方法實(shí)現(xiàn)繼承。特別需要注意的是,調(diào)用抽象工廠方法后不要忘記重寫(xiě)抽象方法,否則在子類的實(shí)例中調(diào)用抽象方法會(huì)報(bào)錯(cuò)。

我們來(lái)分別對(duì)這三種類進(jìn)行實(shí)例化,檢測(cè)抽象工廠方法是實(shí)現(xiàn)了類簇的管理。

//實(shí)例化微信用戶
let wechatUserA = new UserOfWechat("微信小李");
console.log(wechatUserA.getName(), wechatUserA.type); //微信小李 wechat
let wechatUserB = new UserOfWechat("微信小王");
console.log(wechatUserB.getName(), wechatUserB.type); //微信小王 wechat

//實(shí)例化qq用戶
let qqUserA = new UserOfQq("QQ小李");
console.log(qqUserA.getName(), qqUserA.type); //QQ小李 qq
let qqUserB = new UserOfQq("QQ小王");
console.log(qqUserB.getName(), qqUserB.type); //QQ小王 qq

//實(shí)例化微博用戶
let weiboUserA =new UserOfWeibo("微博小李");
console.log(weiboUserA.getName(), weiboUserA.type); //微博小李 weibo
let weiboUserB =new UserOfWeibo("微博小王");
console.log(weiboUserB.getName(), weiboUserB.type); //微博小王 weibo

從打印結(jié)果上看,AccountAbstractFactory這個(gè)抽象工廠很好的實(shí)現(xiàn)了它的作用,將不同用戶賬戶按照社交媒體這一個(gè)類簇進(jìn)行了分類。這就是抽象工廠的作用,它不直接創(chuàng)建實(shí)例,而是通過(guò)類的繼承進(jìn)行類簇的管理。抽象工廠模式一般用在多人協(xié)作的超大型項(xiàng)目中,并且嚴(yán)格的要求項(xiàng)目以面向?qū)ο蟮乃枷脒M(jìn)行完成。

2 ES6中的工廠模式

ES6中給我們提供了class新語(yǔ)法,雖然class本質(zhì)上是一顆語(yǔ)法糖,并也沒(méi)有改變JavaScript是使用原型繼承的語(yǔ)言,但是確實(shí)讓對(duì)象的創(chuàng)建和繼承的過(guò)程變得更加的清晰和易讀。下面我們使用ES6的新語(yǔ)法來(lái)重寫(xiě)上面的例子。

2.1 ES6重寫(xiě)簡(jiǎn)單工廠模式

使用ES6重寫(xiě)簡(jiǎn)單工廠模式時(shí),我們不再使用構(gòu)造函數(shù)創(chuàng)建對(duì)象,而是使用class的新語(yǔ)法,并使用static關(guān)鍵字將簡(jiǎn)單工廠封裝到User類的靜態(tài)方法中:

//User類
class User {
  //構(gòu)造器
  constructor(opt) {
    this.name = opt.name;
    this.viewPage = opt.viewPage;
  }

  //靜態(tài)方法
  static getInstance(role) {
    switch (role) {
      case "superAdmin":
        return new User({ name: "超級(jí)管理員", viewPage: ["首頁(yè)", "通訊錄", "發(fā)現(xiàn)頁(yè)", "應(yīng)用數(shù)據(jù)", "權(quán)限管理"] });
        break;
      case "admin":
        return new User({ name: "管理員", viewPage: ["首頁(yè)", "通訊錄", "發(fā)現(xiàn)頁(yè)", "應(yīng)用數(shù)據(jù)"] });
        break;
      case "user":
        return new User({ name: "普通用戶", viewPage: ["首頁(yè)", "通訊錄", "發(fā)現(xiàn)頁(yè)"] });
        break;
      default:
        throw new Error("參數(shù)錯(cuò)誤, 可選參數(shù):superAdmin、admin、user")
    }
  }
}

//調(diào)用
let superAdmin = User.getInstance("superAdmin");
let admin = User.getInstance("admin");
let normalUser = User.getInstance("user");
2.2 ES6重寫(xiě)工廠方法模式

在上文中我們提到,工廠方法模式的本意是將實(shí)際創(chuàng)建對(duì)象的工作推遲到子類中,這樣核心類就變成了抽象類。但是JavaScript的abstract是一個(gè)保留字,并沒(méi)有提供抽象類,所以之前我們只是借鑒了工廠方法模式的核心思想。

雖然ES6也沒(méi)有實(shí)現(xiàn)abstract,但是我們可以使用new.target來(lái)模擬出抽象類。new.target指向直接被new執(zhí)行的構(gòu)造函數(shù),我們對(duì)new.target進(jìn)行判斷,如果指向了該類則拋出錯(cuò)誤來(lái)使得該類成為抽象類。下面我們來(lái)改造代碼。

class User {
  constructor(name = "", viewPage = []) {
    if(new.target === User) {
      throw new Error("抽象類不能實(shí)例化!");
    }
    this.name = name;
    this.viewPage = viewPage;
  }
}

class UserFactory extends User {
  constructor(name, viewPage) {
    super(name, viewPage)
  }
  create(role) {
    switch (role) {
      case "superAdmin": 
        return new UserFactory( "超級(jí)管理員", ["首頁(yè)", "通訊錄", "發(fā)現(xiàn)頁(yè)", "應(yīng)用數(shù)據(jù)", "權(quán)限管理"] );
        break;
      case "admin":
        return new UserFactory( "普通用戶", ["首頁(yè)", "通訊錄", "發(fā)現(xiàn)頁(yè)"] );
        break;
      case "user":
        return new UserFactory( "普通用戶", ["首頁(yè)", "通訊錄", "發(fā)現(xiàn)頁(yè)"] );
        break;
      default:
        throw new Error("參數(shù)錯(cuò)誤, 可選參數(shù):superAdmin、admin、user")
    }
  }
}

let userFactory = new UserFactory();
let superAdmin = userFactory.create("superAdmin");
let admin = userFactory.create("admin");
let user = userFactory.create("user");
2.3 ES6重寫(xiě)抽象工廠模式

抽象工廠模式并不直接生成實(shí)例, 而是用于對(duì)產(chǎn)品類簇的創(chuàng)建。我們同樣使用new.target語(yǔ)法來(lái)模擬抽象類,并通過(guò)繼承的方式創(chuàng)建出UserOfWechat, UserOfQq, UserOfWeibo這一系列子類類簇。使用getAbstractUserFactor來(lái)返回指定的類簇。

class User {
  constructor(type) {
    if (new.target === User) {
      throw new Error("抽象類不能實(shí)例化!")
    }
    this.type = type;
  }
}

class UserOfWechat extends User {
  constructor(name) {
    super("wechat");
    this.name = name;
    this.viewPage = ["首頁(yè)", "通訊錄", "發(fā)現(xiàn)頁(yè)"]
  }
}

class UserOfQq extends User {
  constructor(name) {
    super("qq");
    this.name = name;
    this.viewPage = ["首頁(yè)", "通訊錄", "發(fā)現(xiàn)頁(yè)"]
  }
}

class UserOfWeibo extends User {
  constructor(name) {
    super("weibo");
    this.name = name;
    this.viewPage = ["首頁(yè)", "通訊錄", "發(fā)現(xiàn)頁(yè)"]
  }
}

function getAbstractUserFactory(type) {
  switch (type) {
    case "wechat":
      return UserOfWechat;
      break;
    case "qq":
      return UserOfQq;
      break;
    case "weibo":
      return UserOfWeibo;
      break;
    default:
      throw new Error("參數(shù)錯(cuò)誤, 可選參數(shù):superAdmin、admin、user")
  }
}

let WechatUserClass = getAbstractUserFactory("wechat");
let QqUserClass = getAbstractUserFactory("qq");
let WeiboUserClass = getAbstractUserFactory("weibo");

let wechatUser = new WechatUserClass("微信小李");
let qqUser = new QqUserClass("QQ小李");
let weiboUser = new WeiboUserClass("微博小李");
3 工廠模式的項(xiàng)目實(shí)戰(zhàn)應(yīng)用

在實(shí)際的前端業(yè)務(wù)中,最常用的簡(jiǎn)單工廠模式。如果不是超大型的項(xiàng)目,是很難有機(jī)會(huì)使用到工廠方法模式和抽象工廠方法模式的。下面我介紹在Vue項(xiàng)目中實(shí)際使用到的簡(jiǎn)單工廠模式的應(yīng)用。

在普通的vue + vue-router的項(xiàng)目中,我們通常將所有的路由寫(xiě)入到router/index.js這個(gè)文件中。下面的代碼我相信vue的開(kāi)發(fā)者會(huì)非常熟悉,總共有5個(gè)頁(yè)面的路由:

// index.js

import Vue from "vue"
import Router from "vue-router"
import Login from "../components/Login.vue"
import SuperAdmin from "../components/SuperAdmin.vue"
import NormalAdmin from "../components/Admin.vue"
import User from "../components/User.vue"
import NotFound404 from "../components/404.vue"

Vue.use(Router)

export default new Router({
  routes: [
    //重定向到登錄頁(yè)
    {
      path: "/",
      redirect: "/login"
    },
    //登陸頁(yè)
    {
      path: "/login",
      name: "Login",
      component: Login
    },
    //超級(jí)管理員頁(yè)面
    {
      path: "/super-admin",
      name: "SuperAdmin",
      component: SuperAdmin
    },
    //普通管理員頁(yè)面
    {
      path: "/normal-admin",
      name: "NormalAdmin",
      component: NormalAdmin
    },
    //普通用戶頁(yè)面
    {
      path: "/user",
      name: "User",
      component: User
    },
    //404頁(yè)面
    {
      path: "*",
      name: "NotFound404",
      component: NotFound404
    }
  ]
})

當(dāng)涉及權(quán)限管理頁(yè)面的時(shí)候,通常需要在用戶登陸根據(jù)權(quán)限開(kāi)放固定的訪問(wèn)頁(yè)面并進(jìn)行相應(yīng)權(quán)限的頁(yè)面跳轉(zhuǎn)。但是如果我們還是按照老辦法將所有的路由寫(xiě)入到router/index.js這個(gè)文件中,那么低權(quán)限的用戶如果知道高權(quán)限路由時(shí),可以通過(guò)在瀏覽器上輸入url跳轉(zhuǎn)到高權(quán)限的頁(yè)面。所以我們必須在登陸的時(shí)候根據(jù)權(quán)限使用vue-router提供的addRoutes方法給予用戶相對(duì)應(yīng)的路由權(quán)限。這個(gè)時(shí)候就可以使用簡(jiǎn)單工廠方法來(lái)改造上面的代碼。

router/index.js文件中,我們只提供/login這一個(gè)路由頁(yè)面。

//index.js

import Vue from "vue"
import Router from "vue-router"
import Login from "../components/Login.vue"

Vue.use(Router)

export default new Router({
  routes: [
    //重定向到登錄頁(yè)
    {
      path: "/",
      redirect: "/login"
    },
    //登陸頁(yè)
    {
      path: "/login",
      name: "Login",
      component: Login
    }
  ]
})

我們?cè)?b>router/文件夾下新建一個(gè)routerFactory.js文件,導(dǎo)出routerFactory簡(jiǎn)單工廠函數(shù),用于根據(jù)用戶權(quán)限提供路由權(quán)限,代碼如下

//routerFactory.js

import SuperAdmin from "../components/SuperAdmin.vue"
import NormalAdmin from "../components/Admin.vue"
import User from "../components/User.vue"
import NotFound404 from "../components/404.vue"

let AllRoute = [
  //超級(jí)管理員頁(yè)面
  {
    path: "/super-admin",
    name: "SuperAdmin",
    component: SuperAdmin
  },
  //普通管理員頁(yè)面
  {
    path: "/normal-admin",
    name: "NormalAdmin",
    component: NormalAdmin
  },
  //普通用戶頁(yè)面
  {
    path: "/user",
    name: "User",
    component: User
  },
  //404頁(yè)面
  {
    path: "*",
    name: "NotFound404",
    component: NotFound404
  }
]

let routerFactory = (role) => {
  switch (role) {
    case "superAdmin":
      return {
        name: "SuperAdmin",
        route: AllRoute
      };
      break;
    case "normalAdmin":
      return {
        name: "NormalAdmin",
        route: AllRoute.splice(1)
      }
      break;
    case "user":
      return {
        name: "User",
        route:  AllRoute.splice(2)
      }
      break;
    default: 
      throw new Error("參數(shù)錯(cuò)誤! 可選參數(shù): superAdmin, normalAdmin, user")
  }
}

export { routerFactory }

在登陸頁(yè)導(dǎo)入該方法,請(qǐng)求登陸接口后根據(jù)權(quán)限添加路由:

//Login.vue

import {routerFactory} from "../router/routerFactory.js"
export default {
  //... 
  methods: {
    userLogin() {
      //請(qǐng)求登陸接口, 獲取用戶權(quán)限, 根據(jù)權(quán)限調(diào)用this.getRoute方法
      //..
    },
    
    getRoute(role) {
      //根據(jù)權(quán)限調(diào)用routerFactory方法
      let routerObj = routerFactory(role);
      
      //給vue-router添加該權(quán)限所擁有的路由頁(yè)面
      this.$router.addRoutes(routerObj.route);
      
      //跳轉(zhuǎn)到相應(yīng)頁(yè)面
      this.$router.push({name: routerObj.name})
    }
  }
};

在實(shí)際項(xiàng)目中,因?yàn)槭褂?b>this.$router.addRoutes方法添加的路由刷新后不能保存,所以會(huì)導(dǎo)致路由無(wú)法訪問(wèn)。通常的做法是本地加密保存用戶信息,在刷新后獲取本地權(quán)限并解密,根據(jù)權(quán)限重新添加路由。這里因?yàn)楹凸S模式?jīng)]有太大的關(guān)系就不再贅述。

總結(jié)

上面說(shuō)到的三種工廠模式和上文的單例模式一樣,都是屬于創(chuàng)建型的設(shè)計(jì)模式。簡(jiǎn)單工廠模式又叫靜態(tài)工廠方法,用來(lái)創(chuàng)建某一種產(chǎn)品對(duì)象的實(shí)例,用來(lái)創(chuàng)建單一對(duì)象;工廠方法模式是將創(chuàng)建實(shí)例推遲到子類中進(jìn)行;抽象工廠模式是對(duì)類的工廠抽象用來(lái)創(chuàng)建產(chǎn)品類簇,不負(fù)責(zé)創(chuàng)建某一類產(chǎn)品的實(shí)例。在實(shí)際的業(yè)務(wù)中,需要根據(jù)實(shí)際的業(yè)務(wù)復(fù)雜度來(lái)選擇合適的模式。對(duì)于非大型的前端應(yīng)用來(lái)說(shuō),靈活使用簡(jiǎn)單工廠其實(shí)就能解決大部分問(wèn)題。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/115977.html

相關(guān)文章

  • ES6重新認(rèn)識(shí)JavaScript設(shè)計(jì)模式(): 工廠模式

    摘要:簡(jiǎn)單工廠模式簡(jiǎn)單工廠模式又叫靜態(tài)工廠模式,由一個(gè)工廠對(duì)象決定創(chuàng)建某一種產(chǎn)品對(duì)象類的實(shí)例。工廠方法模式工廠方法模式的本意是將實(shí)際創(chuàng)建對(duì)象的工作推遲到子類中,這樣核心類就變成了抽象類。抽象工廠模式一般用在 1 什么是工廠模式? 工廠模式是用來(lái)創(chuàng)建對(duì)象的一種最常用的設(shè)計(jì)模式。我們不暴露創(chuàng)建對(duì)象的具體邏輯,而是將將邏輯封裝在一個(gè)函數(shù)中,那么這個(gè)函數(shù)就可以被視為一個(gè)工廠。工廠模式根據(jù)抽象程度的不...

    szysky 評(píng)論0 收藏0
  • ES6重新認(rèn)識(shí)JavaScript設(shè)計(jì)模式(三): 建造者模式

    摘要:書(shū)籍建造者類調(diào)用建造者高效能人士的七個(gè)習(xí)慣史蒂芬柯維勵(lì)志上面的這個(gè)類和第一個(gè)例子的效果一樣,但是長(zhǎng)度確減少不少,在有更多屬性的時(shí)候,減少的代碼量會(huì)更為明顯。參考內(nèi)容設(shè)計(jì)模式張容銘 showImg(https://segmentfault.com/img/remote/1460000015147692); 1 什么是建造者模式? 建造者模式(Builder)是將一個(gè)復(fù)雜對(duì)象的構(gòu)建層與其表...

    hatlonely 評(píng)論0 收藏0
  • ES6重新認(rèn)識(shí)JavaScript設(shè)計(jì)模式(三): 建造者模式

    摘要:書(shū)籍建造者類調(diào)用建造者高效能人士的七個(gè)習(xí)慣史蒂芬柯維勵(lì)志上面的這個(gè)類和第一個(gè)例子的效果一樣,但是長(zhǎng)度確減少不少,在有更多屬性的時(shí)候,減少的代碼量會(huì)更為明顯。參考內(nèi)容設(shè)計(jì)模式張容銘 showImg(https://segmentfault.com/img/remote/1460000015147692); 1 什么是建造者模式? 建造者模式(Builder)是將一個(gè)復(fù)雜對(duì)象的構(gòu)建層與其表...

    yuanxin 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

閱讀需要支付1元查看
<