ES6 類聊 JavaScript 設(shè)計(jì)模式之創(chuàng)建型模式

本文開始系統(tǒng)性的對(duì) 20 多種 JavaScript 設(shè)計(jì)模式進(jìn)行簡單概述,然后結(jié)合 ES6 類的方式來編寫實(shí)例代碼展示其使用方式。

什么是設(shè)計(jì)模式?

設(shè)計(jì)模式是軟件設(shè)計(jì)中常見問題的解決方案,這些模式很容易重復(fù)使用并且富有表現(xiàn)力。

在軟件工程中,設(shè)計(jì)模式(design pattern)是對(duì)軟件設(shè)計(jì)中普遍存在(反復(fù)出現(xiàn))的各種問題,所提出的解決方案。它并不直接用來完成代碼的編寫,而是描述在各種不同情況下,要怎么解決問題的一種方案。面向?qū)ο笤O(shè)計(jì)模式通常以類別或?qū)ο髞砻枋銎渲械年P(guān)系和相互作用,但不涉及用來完成應(yīng)用程序的特定類別或?qū)ο蟆?mdash;— 維基百科

有三種模式:創(chuàng)建型模式,結(jié)構(gòu)型模式、行為型模式。

  • 創(chuàng)建型模式:解決與創(chuàng)建對(duì)象相關(guān)的問題。
  • 結(jié)構(gòu)型模式:處理實(shí)體之間的關(guān)系,以及它們?nèi)绾喂餐M成一個(gè)更大的結(jié)構(gòu)。
  • 行為型模式:處理對(duì)象如何相互通信和交互。

創(chuàng)建型設(shè)計(jì)模式

創(chuàng)建設(shè)計(jì)模式將創(chuàng)建對(duì)象,而不是直接實(shí)例化對(duì)象。

在軟件工程中,創(chuàng)建型模式是處理對(duì)象創(chuàng)建的設(shè)計(jì)模式,試圖根據(jù)實(shí)際情況使用合適的方式創(chuàng)建對(duì)象,因?yàn)榛镜膶?duì)象創(chuàng)建方式可能會(huì)導(dǎo)致設(shè)計(jì)上的問題,或增加設(shè)計(jì)的復(fù)雜度。創(chuàng)建型模式的關(guān)注點(diǎn)是如何創(chuàng)建對(duì)象,其核心思想是要把對(duì)象的創(chuàng)建和使用相分離。—— 維基百科

  • 工廠模式
  • 抽象工廠
  • 構(gòu)建器模式
  • 原型模式
  • 單例模式

1. 工廠模式

工廠模式定義了一個(gè)用于創(chuàng)建單個(gè)對(duì)象的接口,并讓子類決定要實(shí)例化類。

工廠方法模式(英語:Factory method pattern)是一種實(shí)現(xiàn)了“工廠”概念的面向?qū)ο笤O(shè)計(jì)模式。就像其他創(chuàng)建型模式一樣,它也是處理在不指定對(duì)象具體類型的情況下創(chuàng)建對(duì)象的問題。工廠方法模式的實(shí)質(zhì)是“定義一個(gè)創(chuàng)建對(duì)象的接口,但讓實(shí)現(xiàn)這個(gè)接口的類來決定實(shí)例化哪個(gè)類。—— 維基百科

實(shí)例

以一個(gè)點(diǎn)為例,有一個(gè) Point 類,必須創(chuàng)建一個(gè)笛卡爾點(diǎn)和一個(gè)極點(diǎn)。將定義一個(gè) Point 工廠來完成這項(xiàng)工作。

CoordinateSystem = {
    CARTESIAN:0,
    POLAR:1
};

class Point {
    constructor(x, y) {
        this.x = x;
        this.y = y;
    }

    static get factory() {
        return new PointFactory();
    }
}

現(xiàn)在將創(chuàng)建 Point 工廠,現(xiàn)在將使用工廠:

class Point {
    constructor(x, y) {
        this.x = x;
        this.y = y;
    }

    static get factory() {
        return new PointFactory();
    }
}

class PointFactory {
    static newCartesianPoint(x, y) {
        return new Point(x, y);
    }

    static newPolarPoint(rho, theta) {
        return new Point(rho * Math.cos(theta), rho * Math.sin(theta));
    }
}
const point = PointFactory.newPolarPoint(5, Math.PI / 2);
const point2 = PointFactory.newCartesianPoint(5, 6);
console.log(point);
console.log(point2);

2. 抽象工廠

抽象工廠創(chuàng)建公共對(duì)象的族或組,而不指定它們的具體類。

抽象工廠模式提供了一種方式,可以將一組具有同一主題的單獨(dú)的工廠封裝起來。—— 維基百科

實(shí)例

將使用飲料和飲料制造機(jī)的示例。

class Drink {
    consume() {}
}
class Tea extends Drink {
    consume() {
        console.log("This is tea");
    }
}

class Coffee extends Drink {
    consume() {
        console.log("This is coffee");
    }
}

class DrinkFactory {
    prepare(amount) {}
}

class TeaFactory extends DrinkFactory {
    makeTea() {
        console.log("Tea Created");
        return new Tea();
    }
}

class CoffeeFactory extends DrinkFactory {
    makeCoffee() {
        console.log("Coffee Created");
        return new Coffee();
    }
}
const teaDrinkFactory = new TeaFactory();
const tea = teaDrinkFactory.makeTea();
tea.consume();

const coffeeDrinkFactory = new CoffeeFactory();
const coffee = coffeeDrinkFactory.makeCoffee();
coffee.consume();

3. 構(gòu)建器模式

構(gòu)建器模式從簡單對(duì)象構(gòu)造復(fù)雜對(duì)象。

又名:建造模式,是一種對(duì)象構(gòu)建模式。它可以將復(fù)雜對(duì)象的建造過程抽象出來(抽象類別),使這個(gè)抽象過程的不同實(shí)現(xiàn)方法可以構(gòu)造出不同表現(xiàn)(屬性)的對(duì)象。—— 維基百科

實(shí)例

將使用存儲(chǔ) Person 信息的 person 類的 ab 示例。

class Person {
    constructor() {
        this.streetAddress = this.postcode = this.city = "";
        this.companyName = this.position = "";
        this.annualIncome = 0;
    }

    toString() {
        return `個(gè)人生活在 ${this.streetAddress},${this.city},${this.postcode} ,工作在 ${this.companyName} 作為一名 ${this.position} 收入 ${this.annualIncome}`;
    }
}

現(xiàn)在將創(chuàng)建 Person BuilderPerson Job BuilderPerson Address Builder

class PersonBuilder {
    constructor(person = new Person()) {
        this.person = person;
    }

    get lives() {
        return new PersonAddressBuilder(this.person);
    }

    get works() {
        return new PersonJobBuilder(this.person);
    }

    build() {
        return this.person;
    }
}

class PersonJobBuilder extends PersonBuilder {
    constructor(person) {
        super(person);
    }

    at(companyName) {
        this.person.companyName = companyName;
        return this;
    }

    asA(position) {
        this.person.position = position;
        return this;
    }

    earning(annualIncome) {
        this.person.annualIncome = annualIncome;
        return this;
    }
}

class PersonAddressBuilder extends PersonBuilder {
    constructor(person) {
        super(person);
    }

    at(streetAddress) {
        this.person.streetAddress = streetAddress;
        return this;
    }

    withPostcode(postcode) {
        this.person.postcode = postcode;
        return this;
    }

    in(city) {
        this.person.city = city;
        return this;
    }
}

現(xiàn)在將使用上面定義的構(gòu)建器:

const personBuilder = new PersonBuilder();
const person = personBuilder.lives
    .at("高新南九道")
    .in("深圳")
    .withPostcode("518029")
    .works.at("字節(jié)跳動(dòng)")
    .asA("工程師")
    .earning(10000)
    .build();

console.log(person.toString()); // 個(gè)人生活在 高新南九道,深圳,518029 ,工作在 字節(jié)跳動(dòng) 作為一名 工程師 收入 10000

4. 原型模式

原型模式從現(xiàn)有對(duì)象創(chuàng)建新對(duì)象。

其特點(diǎn)在于通過“復(fù)制”一個(gè)已經(jīng)存在的實(shí)例來返回新的實(shí)例,而不是新建實(shí)例。被復(fù)制的實(shí)例就是我們所稱的“原型”,這個(gè)原型是可定制的。—— 維基百科

實(shí)例

使用汽車的例子。

class Car {
    constructor(name, model) {
        this.name = name;
        this.model = model;
    }

    setName(name) {
        console.log(name);
        this.name = name;
    }

    clone() {
        return new Car(this.name, this.model);
    }
}

const car = new Car();
car.setName("閃電");

const car2 = car.clone();
car2.setName("麥昆");

5. 單例模式

單例模式確保只為特定類創(chuàng)建一個(gè)對(duì)象。

在軟件工程中,單例模式是一種軟件設(shè)計(jì)模式,它將類的實(shí)例化限制為一個(gè)“單一”實(shí)例。當(dāng)需要一個(gè)對(duì)象來協(xié)調(diào)整個(gè)系統(tǒng)的動(dòng)作時(shí),這很有用。 —— 維基百科

實(shí)例

創(chuàng)建一個(gè)單例類。

class Singleton {
    constructor() {
        const instance = this.constructor.instance;
        if (instance) {
            return instance;
        }
        this.constructor.instance = this;
    }

    say() {
        console.log("Saying……");
    }
}

const s1 = new Singleton();
const s2 = new Singleton();
console.log("Are they same?" + (s1 === s2));

s1.say();