TypeScript設計模式之工廠

看看用TypeScript怎樣實現常見的設計模式,順便複習一下。
學模式最重要的不是記UML,而是知道什麼模式能夠解決什麼樣的問題,在作項目時碰到問題能夠想到用哪一個模式能夠解決,UML忘了能夠查,思想記住就好。
這裏儘可能用原創的,實際中能碰到的例子來講明模式的特色和用處。設計模式

簡單工廠模式 Simple Factory

特色:把同類型產品對象的建立集中到一塊兒,經過工廠來建立,添加新產品時只需加到工廠裏便可,也就是把變化封裝起來,同時還能夠隱藏產品細節。

用處:要new多個同一類型對象時能夠考慮使用簡單工廠。

注意:對象須要繼承自同一個接口。

下面用TypeScript寫一個槍工廠來看看簡單工廠模式:架構

enum GunType{
    AK,
    M4A1,
}

interface Shootable{
    shoot();
}

abstract class Gun implements Shootable{ // 抽象產品 - 槍
    abstract shoot();
}

class AK47 extends Gun{ //具體產品 - AK47
    shoot(){
        console.log('ak47 shoot.');
    }
}

class M4A1 extends Gun{ //具體產品 - M4A1
    shoot(){
        console.log('m4a1 shoot.');
    }
}

class GunFactory{

    static createGun(type: GunType): Gun{
        switch(type){
            case GunType.AK:
                return new AK47();
            case GunType.M4A1:
                return new M4A1();
            default:
                throw Error('not support this gun yet');
        }
    }
}

GunFactory.createGun(GunType.AK).shoot();
GunFactory.createGun(GunType.M4A1).shoot();

//輸出
ak47 shoot.
m4a1 shoot.

上面代碼GunFactory工廠就是根據類型來建立不一樣的產品,使用的時候只須要引入這個工廠和接口便可。
這樣就把變化封裝到了工廠中,若是之後要支持狙擊槍,只須要加個實現Gun接口的Sniper類就能夠了。app

工廠方法模式 Factory Method

特色:把工廠抽象出來,讓子工廠來決定怎麼生產產品, 每一個產品都由本身的工廠生產。

用處:當產品對象須要進行不一樣的加工時能夠考慮工廠方法。

注意:這不是所謂的簡單工廠的升級版,二者有不一樣的應用場景。

繼續用TypeScript寫一個槍工廠來看看工廠方法模式:框架

interface Shootable{
    shoot();
}

abstract class Gun implements Shootable{ // 抽象產品 - 槍
    abstract shoot();
}

class AK47 extends Gun{ //具體產品 - AK47
    shoot(){
        console.log('ak47 shoot.');
    }
}

class M4A1 extends Gun{ //具體產品 - M4A1
    shoot(){
        console.log('m4a1 shoot.');
    }
}

abstract class GunFactory{ //抽象槍工廠
    abstract create(): Gun;
}

class AK47Factory extends GunFactory{ //Ak47工廠
    create(): Gun{
        let gun = new AK47();  // 生產Ak47
        console.log('produce ak47 gun.');
        this.clean(gun);       // 清理工做
        this.applyTungOil(gun);// Ak47是木頭槍托,塗上桐油
        return gun;
    }

    private clean(gun: Gun){
        //清洗
        console.log('clean gun.');
    }

    private applyTungOil(gun: Gun){
        //塗上桐油
        console.log('apply tung oil.');
    }
}

class M4A1Factory extends GunFactory{ //M4A1工廠
    create(): Gun{
        let gun = new M4A1();   // 生產M4A1
        console.log('produce m4a1 gun.');
        this.clean(gun);        // 清理工做
        this.sprayPaint(gun);   // M4是全金屬,噴上漆
        return gun;
    }

    private clean(gun: Gun){
        //清洗
        console.log('clean gun.');
    }

    private sprayPaint(gun: Gun){
        //噴漆
        console.log('spray paint.');
    }
}

let ak47 = new AK47Factory().create();
ak47.shoot();

let m4a1 = new M4A1Factory().create();
m4a1.shoot();

//output
produce ak47 gun.
clean gun.
apply tung oil.
ak47 shoot.

produce m4a1 gun.
clean gun.
spray paint.
m4a1 shoot.

能夠看到Ak47和M4A1在生產出來後的處理不同,Ak須要塗桐油,M4須要噴漆,用簡單工廠就比較難作到,因此就每一個產品都弄個工廠來封裝各本身的生產過程。
另外的好處是當加入其餘槍好比沙漠之鷹時,再加一個產品和產品工廠就行了,並不須要改變現有代碼,算是作到了遵照開閉原則。
缺點也明顯,增長一個產品就須要多加兩個類,增長了代碼複雜性。this

抽象工廠模式 Abstract Factory

特色:一樣隱藏了具體產品的生產,不過生產的是多種類產品。

用處:當須要生產的是一個產品族,而且產品之間或多或少有關聯時能夠考慮抽象工廠方法。

注意:和工廠方法的區別,工廠方法是一個產品, 而抽象工廠是產品族,線和麪的區別。

繼續用槍,外加子彈,用TypeScript寫一個抽象槍工廠來看看抽象工廠模式:設計

interface Shootable{
    shoot();
}

abstract class Gun implements Shootable{ // 抽象產品 - 槍
    private _bullet: Bullet;

    addBullet(bullet: Bullet){
        this._bullet = bullet;
    }

    abstract shoot();
}

class AK47 extends Gun{ //具體產品 - AK47

    shoot(){
        console.log(`ak47 shoot with ${this._bullet}.`);
    }
}

class M4A1 extends Gun{ //具體產品 - M4A1
    
    shoot(){
        console.log(`m4a1 shoot with ${this._bullet}.`);
    }
}

abstract class Bullet{ // 抽象子彈
    abstract name: string;
}

class AkBullet{ // AK 子彈
    name: string = 'ak bullet';
}

class M4Bullet{ // m4a1 子彈
    name: string = 'm4a1 bullet';
}

abstract class ArmFactory{ //抽象軍工廠
    abstract createGun(): Gun;
    abstract createBullet(): Bullet;
}

class AK47Factory extends ArmFactory{
    createGun(): Gun{
        let gun = new AK47();  // 生產Ak47
        console.log('produce ak47 gun.');
        this.clean(gun);       // 清理工做
        this.applyTungOil(gun);// Ak47是木頭槍托,塗上桐油
        return gun;
    }

    private clean(gun: Gun){
        //清洗
        console.log('clean gun.');
    }

    private applyTungOil(gun: Gun){
        //塗上桐油
        console.log('apply tung oil.');
    }

    createBullet(): Bullet{
        return new AkBullet();
    }
}

class M4A1Factory extends ArmFactory{ //M4A1工廠
    createGun(): Gun{
        let gun = new M4A1();   // 生產M4A1
        console.log('produce m4a1 gun.');
        this.clean(gun);        // 清理工做
        this.sprayPaint(gun);   // M4是全金屬,噴上漆
        return gun;
    }

    private clean(gun: Gun){
        //清洗
        console.log('clean gun.');
    }

    private sprayPaint(gun: Gun){
        //噴漆
        console.log('spray paint.');
    }

    createBullet(): Bullet{
        return new M4Bullet();
    }
}

//使用
function shoot(gun: Gun, bullet: Bullet) // 使用生產的槍和子彈
{
    gun.addBullet(bullet);
    gun.shoot();
}

let akFactory = new AK47Factory();
shoot(akFactory.createGun(), akFactory.createBullet());

let m4a1Factory = new M4A1Factory();
shoot(m4a1Factory.createGun(), m4a1Factory.createBullet());

//輸出
produce ak47 gun.
clean gun.
apply tung oil.
add bullet: ak bullet
ak47 shoot with ak bullet.

produce m4a1 gun.
clean gun.
spray paint.
add bullet: m4a1 bullet
m4a1 shoot with m4a1 bullet.

工廠除了生產槍外還生產子彈,子彈和槍算是一個產品族,使用者接觸到的只有抽象工廠和抽象產品,隱藏了具體實現細節。
在大的框架下面有不少小項目時用抽象工廠配合如動態對象生成之類的技術就能夠很容易實現靈活的架構。code

相關文章
相關標籤/搜索