整合營銷服務(wù)商

          電腦端+手機(jī)端+微信端=數(shù)據(jù)同步管理

          免費(fèi)咨詢熱線:

          Java設(shè)計(jì)模式3:工廠方法模式

          廠方法模式

          工廠方法模式是類的創(chuàng)建模式。工廠方法模式的用意是定義一個創(chuàng)建產(chǎn)品對象的工廠接口,將實(shí)際創(chuàng)建工廠推遲到子類中

          工廠方法模式

          工廠方法模式是對簡單工廠模式進(jìn)一步抽象的結(jié)果。

          假如是不使用反射的工廠方法模式,那么所有的if...

          else if...else都放在工廠類中,勢必造成工廠類的無限臃腫

          這時候就需要工廠方法模式來處理這個問題了。工廠方法模式中,核心的工廠類不再負(fù)責(zé)所有對象的創(chuàng)建,而是將具體的創(chuàng)建工作交給子類去做。這個類則搖身一變變成了一個抽象工廠角色,僅僅負(fù)責(zé)給出具體工廠子類必須實(shí)現(xiàn)的接口。

          這一步的改進(jìn),使得系統(tǒng)可以在不修改具體工廠角色的情況下引入新的產(chǎn)品。

          工廠方法模式結(jié)構(gòu)

          使用工廠方法模式的系統(tǒng)涉及到以下角色:

          1、抽象工廠角色

          擔(dān)任這個角色的是工廠方法模式的核心,任何在模式中創(chuàng)建對象的工廠類必須實(shí)現(xiàn)這個接口

          2、具體工廠角色

          擔(dān)任這個角色的是實(shí)現(xiàn)了工廠接口的具體Java類,具體工廠角色與業(yè)務(wù)密切相關(guān),并且隨著使用者的調(diào)用以創(chuàng)建導(dǎo)出類

          3、抽象導(dǎo)出角色

          工廠方法模式所創(chuàng)建的對象的超類

          4、具體導(dǎo)出角色

          這個角色實(shí)現(xiàn)了抽象導(dǎo)出角色所聲明的接口,工廠方法模式所創(chuàng)建的每一個對象都是某個具體角色導(dǎo)出角色的實(shí)例

          工廠方法模式的示例

          有一個抽象工廠,導(dǎo)出文件的工廠:

          它有兩個實(shí)現(xiàn)類,分別是導(dǎo)出HTML文件的工廠和導(dǎo)出PDF文件的工廠:

          抽象產(chǎn)品角色,一個導(dǎo)出文件:

          具體產(chǎn)品角色:

          模擬客戶端調(diào)用,實(shí)例化出一個具體的工廠角色,根據(jù)傳入的參數(shù)返回不同的產(chǎn)品角色:

          返回結(jié)果為:

          導(dǎo)出財(cái)務(wù)版HTML文件
          

          當(dāng)然,也可以修改代碼,看自己喜好,實(shí)例化出不同的子類并且調(diào)用export方法打印。

          工廠方法模式在Java中的應(yīng)用及解讀

          拿ThreadFactory舉個例子,顧名思義,這是一個生產(chǎn)線程的接口:

          具體的線程工廠可以implements這個接口并實(shí)現(xiàn)newThread(Runnable r)方法,來生產(chǎn)具體線程工廠想要生產(chǎn)的線程。JDK在Executors給開發(fā)者提供了一個靜態(tài)內(nèi)部類DefaultThreadFactory,當(dāng)然開發(fā)者也可以自行實(shí)現(xiàn)這個接口,寫自定義的線程工廠。

          總結(jié)

          對于系統(tǒng)的設(shè)計(jì)應(yīng)該足夠靈活并盡可能降低代碼之間的耦合度,當(dāng)修改或增加一個新的功能時,使得使用者盡可能修改少的地方即可。假如設(shè)計(jì)不夠靈活,將無法面對多變的需求,可能一個極小的需求變更,都會使代碼結(jié)構(gòu)發(fā)生改變,并導(dǎo)致其他使用的人都要修改他們的代碼。牽一發(fā)而動全身,系統(tǒng)日后的維護(hù)將變得艱難。



          ava設(shè)計(jì)模式

          前言:

          本系列文章共23篇,詳細(xì)介紹GOF (Gang Of Four)所定義的23種設(shè)計(jì)模式。共分為三大類對應(yīng)標(biāo)題中的3大招,每類中的每一種設(shè)計(jì)模式對應(yīng)3大招中的某一式:

          第1招-創(chuàng)建型(共5式):單例模式,工廠方法模式,抽象工廠模式,建造者模式,原型模式;

          第2招-行為型(共11式):觀察者模式,策略模式,命令模式,狀態(tài)模式,解釋器模式,迭代器模式,中介者模式,訪問者模式,備忘錄模式,責(zé)任鏈模式,模板方法模式;

          第3招-結(jié)構(gòu)型(共7式):適配器模式,外觀模式,代理模式,裝飾者模式,組合模式,橋接模式,享元模式。

          UML (Unified Modeling Language, 統(tǒng)一建模語言):9大圖——構(gòu)件圖、類圖、對象圖、序列圖、協(xié)作圖、活動圖、狀態(tài)機(jī)圖、用例圖、部署圖;6關(guān)系——泛化=實(shí)現(xiàn)>組合>聚合>關(guān)聯(lián)>依賴。

          OO(Object-Oriented, 面向?qū)ο?:面向?qū)ο蟮某绦蛟O(shè)計(jì)方法將數(shù)據(jù)及對數(shù)據(jù)的操作封裝在一起形成一個相互依賴不可分離的整體,即對象;對同類型的對象抽象出其共性形成類。

          內(nèi)容摘要:

          1. 定義

          2. 應(yīng)用場景

          3. 優(yōu)缺點(diǎn)

          4. Java代碼實(shí)例

          5. 小結(jié)

          一、定義

          工廠方法模式:對象的工廠,將類的實(shí)例化過程延遲到子類進(jìn)行。

          說到工廠模式就不得不提一下工廠模式三姐妹,簡單工廠模式、工廠方法模式和抽象工廠模式。其中簡單工廠模式存在諸多違背設(shè)計(jì)原則的問題,未被列入23種設(shè)計(jì)模式。而工廠方法模式解決了這些問題,特別是“開放關(guān)閉原則”,提供了工廠類的抽象,實(shí)現(xiàn)了可擴(kuò)展性。抽象工廠模式不是本文的重點(diǎn),留到下節(jié)介紹。

          工廠方法模式涉及到四個角色:具體產(chǎn)品、抽象產(chǎn)品、具體工廠、抽象工廠。



          工廠方法模式UML圖

          二、應(yīng)用場景

          1. 產(chǎn)品種類不確定,后期可能添加新的產(chǎn)品時;

          2. 當(dāng)前類并不知道需要創(chuàng)建的是什么子類時;

          3. 不想在父類進(jìn)行實(shí)例化工作,想讓子類決定時。

          三、優(yōu)缺點(diǎn)

          優(yōu)點(diǎn):

          1. 良好的擴(kuò)展性,當(dāng)需要添加新的產(chǎn)品時無需修改原來的類,只需添加一個新的產(chǎn)品類和一個工廠類即可;

          2. 代碼結(jié)構(gòu)清晰,產(chǎn)品類是產(chǎn)品類,工廠負(fù)責(zé)創(chuàng)建,客戶端無需知道各種細(xì)節(jié),解耦了產(chǎn)品的創(chuàng)建過程;

          3. 增加了維護(hù)性,將創(chuàng)建過程放到了工廠類里,某一產(chǎn)品的創(chuàng)建發(fā)生變化時不會影響產(chǎn)品本身;

          缺點(diǎn):

          1. 類的個數(shù)爆發(fā)式增長,每添加一種產(chǎn)品就需要添加兩個類,如果產(chǎn)品過多則導(dǎo)致類過多,增加類定義的內(nèi)存開銷;

          四、Java代碼實(shí)例

          在實(shí)現(xiàn)工廠方法模式這前我們先來看一下簡單工廠模式:

          1.創(chuàng)建抽象產(chǎn)品IPhone;

          2.創(chuàng)建具體產(chǎn)品MiPhone和ApplePhone;



          抽象產(chǎn)品和具體產(chǎn)品

          3.創(chuàng)建簡單工廠PhoneFactory;

          4.使用工廠類進(jìn)行創(chuàng)建產(chǎn)品;



          簡單工廠類及客戶端類


          實(shí)現(xiàn)工廠方法模式需要四步:

          1.定義產(chǎn)品接口;

          2.添加具體產(chǎn)品實(shí)現(xiàn);



          抽象產(chǎn)品及具體產(chǎn)品

          3.定義創(chuàng)建工廠接口;

          4.添加具體工廠實(shí)現(xiàn);

          抽象工廠和具體工廠

          5.客戶端使用。



          客戶端使用

          五、小結(jié)

          工廠模式三姐妹中最常用的是簡單工廠模式,但簡單工廠模式違背了設(shè)計(jì)原則中的開放關(guān)閉原則。而工廠方法模式解決了此問題,并且完美使用了里氏替換原則和依賴倒置原則。對于可能出現(xiàn)多種類別的實(shí)例實(shí)現(xiàn)時,建議使用工廠方法模式進(jìn)行解耦。

          . 介紹

          工廠模式(Factory Pattern),根據(jù)不同的名稱輸入返回不同類的實(shí)例,一般用來創(chuàng)建同一類對象。工廠模式的主要思想是將對象的創(chuàng)建與對象的實(shí)現(xiàn)分離。

          2. 生活中的示例?

          • 我們?nèi)?KFC 購買漢堡,只需直接點(diǎn)餐、取餐,不用自己親手做
          • KFC 要「封裝」做漢堡的工作,做好直接給購買者

          在類似場景中,這些例子有以下特點(diǎn):

          • 訪問者只需要知道產(chǎn)品名,就可以從工廠獲得對應(yīng)實(shí)例。
          • 訪問者不關(guān)心實(shí)例創(chuàng)建過程。

          3. 分類?

          工廠模式分為簡單工廠模式、工廠方法模式、抽象工廠模式。

          4. 簡單工廠模式?

          簡單工廠模式是由一個工廠對象決定創(chuàng)建出哪一種產(chǎn)品類的實(shí)例

          簡單工廠模式包含如下角色:

          • Factory:工廠角色 工廠角色負(fù)責(zé)實(shí)現(xiàn)創(chuàng)建所有實(shí)例的內(nèi)部邏輯
          • Product:抽象產(chǎn)品角色 抽象產(chǎn)品角色是所創(chuàng)建的所有對象的父類,負(fù)責(zé)描述所有實(shí)例所共有的公共接口
          • ConcreteProduct:具體產(chǎn)品角色 具體產(chǎn)品角色是創(chuàng)建目標(biāo),所有創(chuàng)建的對象都充當(dāng)這個角色的某個具體類的實(shí)例。

          4.1 實(shí)現(xiàn)?

          類圖: AmericanoCoffee、LatteCoffee和CappuccinoCoffee都是繼承Coffee

          代碼

          abstract class Coffee {
             constructor(public name: string) {
          
             }
          }
          class AmericanoCoffee extends Coffee {
             constructor(public name: string) {
                 super(name);
             }
          }
          class LatteCoffee extends Coffee {
             constructor(public name: string) {
                 super(name);
             }
          }
          class CappuccinoCoffee extends Coffee {
             constructor(public name: string) {
                 super(name);
             }
          }
          
          class Café {
             static order(name: string) {
                 switch (name) {
                     case 'Americano':
                         return new AmericanoCoffee('美式咖啡');
                     case 'Latte':
                         return new LatteCoffee('拿鐵咖啡');
                     case 'Cappuccino':
                         return new LatteCoffee('卡布奇諾');
                     default:
                         return null;
                 }
             }
          }
          console.log(Café.order('Americano'));
          console.log(Café.order('Latte'));
          console.log(Café.order('Cappuccino'));
          

          4.2 前端應(yīng)用場景?

          4.2.1 jQuery?

          jQuery

          class jQuery{
              constructor(selector){
                  let elements = Array.from(document.querySelectorAll(selector));
                  let length = elements?elements.length:0;
                  for(let i=0;i<length;i++){
                      this[i]=elements[i];
                  }
                  this.length = length;
              }
              html(html){
                  if(html){
                     this[0].innerHTML=html;
                  }else{
                    return this[0].innerHTML;
                  }
              }
          }
          window.$ = function(selector){
             return new jQuery(selector);
          }
          

          4.2.2 Vue/React 源碼中的工廠模式?

          和原生的 document.createElement 類似,Vue 和 React 這種具有虛擬 DOM 樹(Virtual Dom Tree)機(jī)制的框架在生成虛擬 DOM 的時候,都提供了 createElement 方法用來生成 VNode,用來作為真實(shí) DOM 節(jié)點(diǎn)的映射

          // Vue
          createElement('h3', { class: 'main-title' }, [
            createElement('img', { class: 'avatar', attrs: { src: '../avatar.jpg' } }),
            createElement('p', { class: 'user-desc' }, '放棄不難,但堅(jiān)持一定很酷')
          ])
          
          // React
          React.createElement('h3', { className: 'user-info' },
            React.createElement('img', { src: '../avatar.jpg', className: 'avatar' }),
            React.createElement('p', { className: 'user-desc' }, '放棄不難,但堅(jiān)持一定很酷')
          )
          
          

          createElement 函數(shù)結(jié)構(gòu)大概如下:

          class Vnode (tag, data, children) { ... }
          
          function createElement(tag, data, children) {
            return new Vnode(tag, data, children)
          }
          
          

          可以看到 createElement 函數(shù)內(nèi)會進(jìn)行 VNode 的具體創(chuàng)建,創(chuàng)建的過程是很復(fù)雜的,而框架提供的 createElement 工廠方法封裝了復(fù)雜的創(chuàng)建與驗(yàn)證過程,對于使用者來說就很方便了。

          4.2.3 vue-router 源碼中的工廠模式?

          工廠模式在源碼中應(yīng)用頻繁,以 vue-router 中的源碼為例,代碼位置:vue-router/src/index.js

          // src/index.js
          export default class VueRouter {
            constructor(options) {
              this.mode = mode    // 路由模式
                  
              switch (mode) {     // 簡單工廠
                case 'history':   // history 方式
                  this.history = new HTML5History(this, options.base)
                  break
                case 'hash':      // hash 方式
                  this.history = new HashHistory(this, options.base, this.fallback)
                  break
                case 'abstract':  // abstract 方式
                  this.history = new AbstractHistory(this, options.base)
                  break
                default:
                  // ... 初始化失敗報(bào)錯
              }
            }
          }
          

          稍微解釋一下這里的源碼。mode 是路由創(chuàng)建的模式,這里有三種 History、Hash、Abstract,前兩種我們已經(jīng)很熟悉了,History 是 H5 的路由方式,Hash 是路由中帶 # 的路由方式,Abstract 代表非瀏覽器環(huán)境中路由方式,比如 Node、weex 等;this.history 用來保存路由實(shí)例,vue-router 中使用了工廠模式的思想來獲得響應(yīng)路由控制類的實(shí)例。

          源碼里沒有把工廠方法的產(chǎn)品創(chuàng)建流程封裝出來,而是直接將產(chǎn)品實(shí)例的創(chuàng)建流程暴露在 VueRouter 的構(gòu)造函數(shù)中,在被 new 的時候創(chuàng)建對應(yīng)產(chǎn)品實(shí)例,相當(dāng)于 VueRouter的構(gòu)造函數(shù)就是一個工廠方法。

          如果一個系統(tǒng)不是 SPA (Single Page Application,單頁應(yīng)用),而是是 MPA(Multi Page Application,多頁應(yīng)用),那么就需要創(chuàng)建多個 VueRouter 的實(shí)例,此時 VueRouter 的構(gòu)造函數(shù)也就是工廠方法將會被多次執(zhí)行,以分別獲得不同實(shí)例。

          4.3 簡單工廠模式的優(yōu)缺點(diǎn)?

          4.3.1 優(yōu)點(diǎn)?

          • 工廠類含有必要的判斷邏輯,可以決定在什么時候創(chuàng)建哪一個產(chǎn)品類的實(shí)例,客戶端可以免除直接創(chuàng)建產(chǎn)品對象的責(zé)任,而僅僅“消費(fèi)”產(chǎn)品;簡單工廠模式通過這種做法實(shí)現(xiàn)了對責(zé)任的分割,它提供了專門的工廠類用于創(chuàng)建對象。
          • 客戶端無須知道所創(chuàng)建的具體產(chǎn)品類的類名,只需要知道具體產(chǎn)品類所對應(yīng)的參數(shù)即可,對于一些復(fù)雜的類名,通過簡單工廠模式可以減少使用者的記憶量。

          4.3.2 缺點(diǎn)?

          • 工廠負(fù)責(zé)所有產(chǎn)品的創(chuàng)建:如果產(chǎn)品的種類非常多switch case的判斷會變得非常多
          • 耦合和依賴于具體的實(shí)現(xiàn):不符合開放—封閉原則,如果要增加或刪除一個產(chǎn)品種類,就要修改switch case的判斷代碼

          5. 工廠方法模式?

          簡單工廠模式是根據(jù)輸入的不同返回不同產(chǎn)品的實(shí)例;而工廠方式的主要思想是增加抽象工廠類,將不同產(chǎn)品的創(chuàng)建分離到不同的工廠中,工廠類的職責(zé)比較單一。

          • 工廠方法模式Factory Method,又稱多態(tài)性工廠模式。
          • 在工廠方法模式中,核心的工廠類不再負(fù)責(zé)所有的產(chǎn)品的創(chuàng)建,而是將具體創(chuàng)建的工作交給工廠子類去做。

          5.1 類圖?

          5.2 代碼?

          abstract class Coffee {
              constructor(public name: string) {
          
              }
          }
          abstract class Factory {
              abstract createCoffee(): Coffee;
          }
          class AmericanoCoffee extends Coffee {
              constructor(public name: string) {
                  super(name);
              }
          }
          
          class AmericanoCoffeeFactory extends Factory {
              createCoffee() {
                  return new AmericanoCoffee('美式咖啡')
              }
          }
          
          class LatteCoffee extends Coffee {
              constructor(public name: string) {
                  super(name);
              }
          }
          class LatteCoffeeFactory extends Factory {
              createCoffee() {
                  return new LatteCoffee('拿鐵咖啡')
              }
          }
          class CappuccinoCoffee extends Coffee {
              constructor(public name: string) {
                  super(name);
              }
          }
          class CappuccinoFactory extends Factory {
              createCoffee() {
                  return new CappuccinoCoffee('卡布奇諾')
              }
          }
          class Café {
              static order(name: string) {
                  switch (name) {
                      case 'Americano':
                          return new AmericanoCoffeeFactory().createCoffee();
                      case 'Latte':
                          return new LatteCoffeeFactory().createCoffee();
                      case 'Cappuccino':
                          return new CappuccinoFactory().createCoffee();
                      default:
                          return null;
                  }
              }
          }
          console.log(Café.order('Americano'));
          console.log(Café.order('Latte'));
          console.log(Café.order('Cappuccino'));
          

          5.3 改進(jìn)?

          • 上面的方案雖然具體創(chuàng)建的工作交給工廠子類去做,抽象工廠不在負(fù)責(zé)創(chuàng)建具體的產(chǎn)品;但是新增產(chǎn)品是還是需要添加switch case。
          • 通過引入Map配置文件,可以在不修改任何客戶端代碼的情況下更換和增加新的具體產(chǎn)品類,在一定程度上提高了系統(tǒng)的靈活性。
          const settings={
              'Americano': AmericanoCoffeeFactory,
              'Latte': LatteCoffeeFactory,
              'Cappuccino': CappuccinoFactory
          }
          
          console.log(new settings('Americano').createCoffee());
          console.log(new settings('Latte').createCoffee());
          console.log(new settings('Cappuccino').createCoffee());
          

          6.設(shè)計(jì)原則驗(yàn)證?

          • 構(gòu)造函數(shù)和創(chuàng)建者分離
          • 符合開放封閉原則

          7.工廠模式的優(yōu)缺點(diǎn)?

          7.1 優(yōu)點(diǎn)?

          • 良好的封裝,代碼結(jié)構(gòu)清晰,訪問者無需知道對象的創(chuàng)建流程,特別是創(chuàng)建比較復(fù)雜的情況下。
          • 擴(kuò)展性優(yōu)良,通過工廠方法隔離了用戶和創(chuàng)建流程隔離,符合開放封閉原則。
          • 解耦了高層邏輯和底層產(chǎn)品類,符合最少知識原則,不需要的就不要去交流。

          7.2 缺點(diǎn)?

          帶來了額外的系統(tǒng)復(fù)雜度,增加了抽象性。

          8.工廠模式的適用場景?

          那在什么時候使用工廠模式呢:

          • 工廠類負(fù)責(zé)創(chuàng)建的對象比較少:由于創(chuàng)建的對象較少,不會造成工廠方法中的業(yè)務(wù)邏輯太過復(fù)雜。
          • 客戶端只知道傳入工廠類的參數(shù),對于如何創(chuàng)建對象不關(guān)心:客戶端既不需要關(guān)心創(chuàng)建細(xì)節(jié),甚至連類名都不需要記住,只需要知道類型所對應(yīng)的參數(shù)。
          • 對象的創(chuàng)建比較復(fù)雜,而訪問者無需知道創(chuàng)建的具體流程。

          什么時候不該用工廠模式:

          濫用只是增加了不必要的系統(tǒng)復(fù)雜度,過猶不及。


          主站蜘蛛池模板: jazzjazz国产精品一区二区| 亚洲国产激情一区二区三区| 精品人妻无码一区二区三区蜜桃一 | 精品视频在线观看一区二区| 国产波霸爆乳一区二区| 无码人妻久久久一区二区三区| 人妻无码视频一区二区三区| 日本精品一区二区三区在线视频一| 国产亚洲一区二区在线观看 | 国精产品一区一区三区有限在线| 国内国外日产一区二区| 国产伦精品一区三区视频| 亚洲.国产.欧美一区二区三区| 中文字幕Av一区乱码| 日美欧韩一区二去三区| 无码国产精品一区二区免费式影视| 一区二区三区视频免费| 国产三级一区二区三区| 国产精品视频一区麻豆| 无码一区二区三区在线观看| 好湿好大硬得深一点动态图91精品福利一区二区 | 竹菊影视欧美日韩一区二区三区四区五区 | 一区二区三区福利视频| 国产一区二区三区播放心情潘金莲 | 日韩精品区一区二区三VR| 国产亚洲一区二区三区在线| 中文字幕一区二区三区在线不卡| 国产一区二区三区免费在线观看| 性色av闺蜜一区二区三区| 无码人妻精品一区二区蜜桃网站| 中文字幕av一区| 日韩三级一区二区三区| 亚洲国产激情一区二区三区 | 日韩人妻无码一区二区三区久久99 | 一区二区三区91| 风间由美性色一区二区三区| 精品亚洲A∨无码一区二区三区| 91精品国产一区二区三区左线 | 成人影片一区免费观看| 狠狠色综合一区二区| 女人和拘做受全程看视频日本综合a一区二区视频|