一区二区三区日韩精品-日韩经典一区二区三区-五月激情综合丁香婷婷-欧美精品中文字幕专区

分享

JavaScript設(shè)計(jì)模式第2篇:工廠模式

 python_lover 2020-02-15

分類

這里工廠模式分為2類:簡單工廠工廠方法,下一節(jié)會介紹第3類工廠模式:抽象工廠。

簡單工廠

定義

簡單工廠:定義一個類來創(chuàng)建其他類的實(shí)例,根據(jù)參數(shù)的不同返回不同類的實(shí)例,通常這些類擁有相同的父類。

例子

假設(shè)現(xiàn)在有 3 款車,Benz、Audi 和 BMW,他們都繼承自父類 Car,并且重寫了父類方法 drive:

class Car {
    drive () {
        console.log('Car drive');
    }
}

class Benz extends Car {
    drive () {
        console.log(`Benz drive`)
    }
}

class Audi extends Car {
    drive () {
        console.log(`Audi drive`)
    }
}

class BMW extends Car {
    drive () {
        console.log(`BMW drive`)
    }
}

我們定義了一個父類 Car,包含一個方法 drive,Benz、Audi 和 BMW 繼承自共同的父類 Car。

那么我們在實(shí)例化這 3 款車的時候,就需要如下調(diào)用:

let benz = new Benz();
let audi = new Audi();
let bmw = new BMW();

benz.drive();       // Benz drive
audi.drive();       // Audi drive
bmw.drive();        // BMW drive

這種寫法就很繁瑣,這時候就用到我們的簡單工廠了,提供一個工廠類:

class SimpleFactory {
    static getCar (type) {
        switch (type) {
            case 'benz':
                return new Benz();
            case 'audi':
                return new Audi();   
            case 'bmw':
                return new BMW();  
        }
    }
}

簡單工廠類 SimpleFactory 提供一個靜態(tài)方法 getCar,我們再實(shí)例化 3 款車的時候,就變成下面這樣了:


let benz = SimpleFactory.getCar('benz');
let audi = SimpleFactory.getCar('audi');
let bmw = SimpleFactory.getCar('bmw');

benz.drive();       // Benz drive
audi.drive();       // Audi drive
bmw.drive();        // BMW drive

這么一看,使用簡單工廠后代碼行數(shù)反而變多了,這種寫法真的有優(yōu)勢嗎?

我們要知道,設(shè)計(jì)模式并不是為了減少代碼行數(shù)而出現(xiàn)的,它是為了使我們的代碼更好擴(kuò)展,更好維護(hù),更方便使用而出現(xiàn)的。那么使用簡單工廠后,有什么好處呢?

簡單工廠,用戶不需要知道具體產(chǎn)品的類名,只需要知道對應(yīng)的參數(shù)即可,對于一些復(fù)雜的類名,可以減少用戶的記憶量,同時用戶無需了解這些對象是如何創(chuàng)建及組織的,有利于整個軟件體系結(jié)構(gòu)的優(yōu)化。

所以,使用簡單工廠,是將類的實(shí)例化交給工廠函數(shù)去做,對外提供統(tǒng)一的方法。我們要養(yǎng)成一個習(xí)慣,在代碼中 new 是一個需要慎重考慮的操作,new 出現(xiàn)的次數(shù)越多,代碼的耦合性就越強(qiáng),可維護(hù)性就越差,簡單工廠,就是在上面做了一層抽象,將 new 的操作封裝了起來,向外提供靜態(tài)方法供用戶調(diào)用,這樣就將耦合集中到了工廠函數(shù)中,而不是暴露在代碼的各個位置。

缺陷

簡單工廠有它的好處,必然也有它的缺點(diǎn),比如下面這種情況:

我們又新增了一類車 Ferrai,就需要在簡單工廠類 SimpleFactory 中再新增一個 case,添加 Ferrari 的實(shí)例化過程。每新增一類車,就要修改簡單工廠類,這樣做其實(shí)違背了設(shè)計(jì)原則中的開閉原則:對擴(kuò)展開放,對修改封閉,同時如果每類車在實(shí)例化之前需要做一些處理邏輯的話,SimpleFactory 會變的越來越復(fù)雜。

所以簡單工廠適用于產(chǎn)品類比較少并且不會頻繁增加的情況,那么有什么方法能解決簡單工廠存在的問題呢?

工廠方法

工廠方法模式是簡單工廠的進(jìn)一步優(yōu)化,我們不再提供一個統(tǒng)一的工廠類來創(chuàng)建所有的對象,而是針對不同的對象提供不同的工廠,也就是說每個對象都有一個與之對應(yīng)的工廠。

定義

工廠方法模式又稱為工廠模式,它的實(shí)質(zhì)是“定義一個創(chuàng)建對象的接口,但讓實(shí)現(xiàn)這個接口的類來決定實(shí)例化哪個類,工廠方法讓類的實(shí)例化推遲到子類中執(zhí)行”。

例子

光看概念還是很難理解,我們沿著上面的簡單工廠來做修改,舉例說明。

還是先定義一個父類 Car,提供一個方法 drive:

class Car {
    drive () {
        console.log('Car drive');
    }
}

每一款車都繼承自父類 Car,并重寫方法 drive:

class Benz extends Car {
    drive () {
        console.log(`Benz drive`)
    }
}

class Audi extends Car {
    drive () {
        console.log(`Audi drive`)
    }
}

class BMW extends Car {
    drive () {
        console.log(`BMW drive`)
    }
}

然后按照定義,我們提供一個創(chuàng)建對象的接口:

class IFactory {
    getCar () {
        throw new Error('不允許直接調(diào)用抽象方法,請自己實(shí)現(xiàn)');
    }
}

每款車都提供一個工廠類,實(shí)現(xiàn)自上述接口,因?yàn)?JavaScript 中沒有 implements,所以用 extends 代替:

class BenzFactory extends IFactory {
    getCar () {
        return new Benz();
    }
}

class AudiFactory extends IFactory {
    getCar () {
        return new Audi();
    }
}

class BMWFactory extends IFactory {
    getCar () {
        return new BMW();
    }
}

這樣當(dāng)我們需要實(shí)例化每款車的時候,就按如下操作:

let benzFactory = new BenzFactory();
let benz = benzFactory.getCar();

let audiFactory = new AudiFactory();
let audi = audiFactory.getCar();

let bmwFactory = new BMWFactory();
let bmw = bmwFactory.getCar();

benz.drive();       // Benz drive
audi.drive();       // Audi drive
bmw.drive();        // BMW drive

我們再來對比一下簡單工廠的實(shí)例化過程:

let benz = SimpleFactory.getCar('benz');
let audi = SimpleFactory.getCar('audi');
let bmw = SimpleFactory.getCar('bmw');

benz.drive();       // Benz drive
audi.drive();       // Audi drive
bmw.drive();        // BMW drive

我們用 UML 類圖來描述一下工廠方法模式:

image.png

可以看到,同樣是為了實(shí)例化一個對象,怎么就變得這么復(fù)雜了呢····我們來總結(jié)一下工廠方法模式的步驟:

  1. 定義產(chǎn)品父類 -- Car
  2. 定義子類實(shí)現(xiàn)父類,并重寫父類方法 -- BenzCar、AudiCar、BMWCar
  3. 定義抽象接口,以及抽象方法 -- IFactory
  4. 定義工廠類,實(shí)現(xiàn)自抽象接口,并且實(shí)現(xiàn)抽象方法 -- BenzFactory、AudiFactory、BMWFactory
  5. new 工廠類,調(diào)用方法進(jìn)行實(shí)例化

那么工廠方法增加了如此多的流程,提高了復(fù)雜度,究竟解決了簡單工廠的什么問題呢?

通過上文可以知道,簡單工廠在新增一款車的時候,需要修改簡單工廠類 SimpleFactory,違背了設(shè)計(jì)模式中的“開閉原則”:對擴(kuò)展開放,對修改封閉。

當(dāng)工廠方法需要新增一款車的時候,比如 Ferrari,只需要定義自己的產(chǎn)品類 Ferrari 以及自己的工廠類 FerrariFactory:

class Ferrari extends Car {
    drive () {
        console.log(`Ferrari drive`)
    }
}

class FerrariFactory extends IFactory {
    getCar () {
        return new Ferrari();
    }
}

let ferrariFactory = new FerrariFactory();
let ferrari = ferrariFactory.getCar();

ferrari.drive();       // Ferrari drive

完全不用修改已有的抽象接口 IFactory,只需要擴(kuò)展實(shí)現(xiàn)自己需要的就可以了,不會影響已有代碼。這就是對擴(kuò)展開放,對修改封閉。

總結(jié)

  1. 簡單工廠模式

    • 解決了用戶多次自己實(shí)例化的問題,屏蔽細(xì)節(jié),提供統(tǒng)一工廠,將實(shí)例化的過程封裝到內(nèi)部,提供給用戶統(tǒng)一的方法,只需要傳遞不同的參數(shù)就可以完成實(shí)例化過程,有利于軟件結(jié)構(gòu)體系的優(yōu)化;
    • 但不足之處是,增加新的子類時,需要修改工廠類,違背了“開閉原則”,并且工廠類會變得越來越臃腫;
    • 簡單工廠模式適用于固定的,不會頻繁新增子類的使用場景
  2. 工廠方法模式

    • 通過在上層再增加一層抽象,提供了接口,每個子類都有自己的工廠類,工廠類實(shí)現(xiàn)自接口,并且實(shí)現(xiàn)了統(tǒng)一的抽象方法,這樣在新增子類的時候,完全不需要修改接口,只需要新增自己的產(chǎn)品類和工廠類就可以了,符合“開閉原則”;
    • 但不足之處也正是如此,持續(xù)的新增子類,導(dǎo)致系統(tǒng)類的個數(shù)將成對增加,在一定程度上增加了系統(tǒng)的復(fù)雜度,同時有更多的類需要編譯和運(yùn)行,會給系統(tǒng)代理一些額外的開銷;
    • 工廠方法模式適用于會頻繁新增子類的復(fù)雜場景;

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多

    中文字幕精品一区二区年下载| 国产盗摄精品一区二区视频| 精产国品一二三区麻豆| 91精品蜜臀一区二区三区| 加勒比日本欧美在线观看| 国产欧洲亚洲日产一区二区| 亚洲午夜精品视频观看| 国产免费观看一区二区| 国产欧美日韩综合精品二区| 好吊日在线视频免费观看| 亚洲欧美黑人一区二区| 69久久精品亚洲一区二区| 欧美亚洲91在线视频| 激情爱爱一区二区三区| 又黄又硬又爽又色的视频 | 丰满少妇被猛烈插入在线观看| 欧美三级精品在线观看| 欧美日韩乱码一区二区三区| 国产黑人一区二区三区| 久久精品一区二区少妇| 亚洲人午夜精品射精日韩| 国产传媒一区二区三区| 欧美做爰猛烈叫床大尺度| 亚洲精品一区二区三区日韩| 国产精品一区二区不卡中文| 色综合久久超碰色婷婷| 丰满人妻熟妇乱又乱精品古代| 国产精品刮毛视频不卡| 久久精品一区二区少妇| 久久国内午夜福利直播| 久久人妻人人澡人人妻| 日本亚洲精品在线观看| 国产av精品一区二区| 久久热这里只有精品视频| 午夜精品成年人免费视频| 五月婷婷欧美中文字幕| 九九热这里只有精品视频| 欧美日本亚欧在线观看| 亚洲精品一区三区三区| 高清国产日韩欧美熟女| 日本久久中文字幕免费|