以《权力的游戏》为例在ES6 +中生成设计模式



设计模式-解决软件开发中最常见问题的方法。在本文中,我们将参考《权力的游戏》研究生成模式。在此处

阅读有关结构模式的信息

生成模式旨在与用于构造对象的机制一起使用,以便在这种情况下以最合适的方式创建对象。

最常见的生成方式如下:

  • 工厂(面料)
  • 抽象(抽象)
  • 构造函数(Builder)
  • 原型(Prototype)
  • 单身人士(单身人士)


工厂是一种模式,它使用所谓的工厂方法来创建对象,而无需确定所创建对象的类。这是什么意思?

想象一下,我们希望能够创建士兵。这些士兵可以来自塔加里安之家,也可以来自兰尼斯特之家。

为此,我们需要:

  • 定义士兵的界面
  • 每种士兵都有一个阶级,可以赋予每个家庭权力
  • 要求创建新士兵的阶级,无论他属于哪个房屋

class Soldier {
    constructor(name) {
        this.name = name
        this.attack = this.attack.bind(this)
    }

    attack() {}
}

class LannisterSoldier extends Soldier {
    attack() {
        return 'Lannister always pays his debts'
    }
}

class TargaryenSoldier extends Soldier {
    attack() {
        return 'Fire and blond'
    }
}

class Spawn {
    constructor(type, name) {
        if (type === 'lannister') return new LannisterSoldier(name)
        else return new TargaryenSoldier(name)
    }
}

(() => {
    const lannister = new Spawn('lannister', 'soldier1')
    const targaryen = new Spawn('targaryen', 'soldier2')
    console.log(lannister.attack())
    console.log(targaryen.attack())
})()

什么时候使用?


  • ,
  • ,


免责声明:基于对象的抽象模板。在函数式编程中很难使用。

该模板使您可以封装一组执行类似任务的单个工厂,而无需定义特定的类。在标准使用中,客户端软件创建抽象工厂的特定实现,然后使用通用工厂接口创建特定对象,作为单个系统的一部分。客户不知道(或对他不重要)他从每个内部工厂收到的特定对象,因为为此使用了公共接口。

想象一下,我们要单独管理每个房屋。每个房屋都应有机会确定王位继承人和他的挚爱。

为此,我们需要:

  • ,

//  
class HeirToTheThrone {
    conctructor(name, isActualOnTheThrone) {
        this.name = name
        this.isActualOnTheThrone = isActualOnTheThrone
        this.getTheThrone = this.getTheThrone.bind(this)
    }
    getTheThrone() {}
}

class HeirToTheThroneLannister extends HeirToTheThrone {
    getTheThrone(){
        console.log('kill all')
    }
}

class HeirToTheThroneTargaryen extends HeirToTheThrone {
    getTheThrone() {
        console.log('burn all')
    }
}

//  
class Subject {
    constructor(name) {
        this.name = name
        this.speak = this.speak.bind(this)
    }
    speak() {}
}

class SubjectLannister extends Subject {
    speak(){
        console.log('i love Cersei')
    }
}

class SubjectTargaryen extends Subject {
    speak(){
        console.log('i love Daenerys')
    }
}

//  
class House {
    constructor() {
        this.getHeir = this.getHeir.bind(this)
        this.getSubject = this.getSubject.bind(this)
    }
    getHeir(){}
    getSubject(){}
}

class Lannister extends House {
    getHeir() {
        return new HeirToTheThroneLannister('Cersei', true)
    }
    getSubject(name) {
        return new SubjectLannister(name)
    }
}

class Targaryen extends House {
    getHeir() {
        return new HeirToTheThroneTargaryen('Daenerys', true)
    }
    getSubject(name) {
        return new SubjectTargaryen(name)
    }
}

(()=>{
    const lannister = new Lannister()
    const targaryen = new Targaryen()
    lannister.getHeir().getTheThrone()
    lannister.getSubject().speak()
    targaryen.getHeir().getTheThrone()
    targaryen.getSubject().speak()
})()

?


  • ,
  • ,


设计者的目的是将复杂对象与其表示分离。由于对象的复杂性,此模板使您可以通过另一个对象(构造函数)分离创建新对象的过程。

想象一下,我们想为每个家庭创建一支舰队。每个家庭将有一定数量的船只和战士。为了便于创建,我们应该能够调用makeNavy方法,该方法将通过设置自动创建我们需要的所有内容。

为此,我们需要:

  • 创建机队的类
  • 构造函数定义的接口
  • 负责创造我军目标的班级
  • 负责创造士兵和船只的班级

class Lannister {
    constructor() {
        this.soldiers = []
        this.ships = []
        this.makeNavy = this.makeNavy.bind(this)
    }
    makeNavy(soldiers, ships) {
        const Build = new ConcreteBuilder()
        for (let i = 0; i < soldiers; i++) {
            this.soldiers.push(Build.createSoldier())
        }
        for (let i = 0; i < ships; i++) {
            this.ships.push(Build.createShip())
        }
    }
}

class Builder {
    createSoldier() {}
    createShip() {}
}

class ConcreteBuilder extends Builder {
    createSoldier() {
        const soldier = new Soldier()
        return soldier
    }
    createShip() {
        const ship = new Ship()
        return ship
    }
}

class Soldier {
    constructor() {
        console.log('soldier created')
    }
}

class Ship {
    constructor() {
        console.log('ship created')
    }
}

(() => {
    const lannister = new Lannister()
    lannister.makeNavy(100, 10)
})()

什么时候使用?


  • 当创建对象的过程非常复杂时,它涉及大量的强制和可选参数
  • 当构造函数参数数量的增加导致设计者数量的增加时
  • 当客户端期望所构造对象的不同视图时

原型


使用原型,您可以确定通过原型继承创建的对象的类型,并使用现有对象的方案创建新对象。这样可以提高性能并最大程度地减少内存丢失。

想象一下,我们想组建一支白人步行者大军。我们对这支部队没有特殊要求。我们只需要它们很多,它们具有相同的特性,并且不会占用很多内存空间。

为此,我们需要:

  • 用于存储有关白步行者信息的类
  • 克隆实例的方法返回相同的方法

class WhiteWalker {
    constructor(force, weight) {
        this.force = force
        this.weight = weight
    }

    clone() {
        console.log('cloned')
        return new WhiteWalker(this.name, this.weight)
    }
}

(()=>{
    const firstWalker = new WhiteWalker()
    const walkers = [firstWalker]
    for(let i=0;i<100;i++){
        walkers.push(firstWalker.clone())
    }
})()

原型的优缺点


优点:

  • 通过消除使用新操作员创建新对象的需求,帮助节省成本,时间和生产力
  • 降低了初始化对象的复杂性:每个类都使用自己的克隆方法
  • 与使用抽象模板时一样,无需分类和创建许多子类来初始化对象
  • 通过更改复制对象的某些属性来创建新对象,从而提高系统灵活性

缺点:

  • 用循环引用克隆复杂的对象是一项艰巨的任务

辛格尔顿


Singleton允许您确保创建的对象是特定类的唯一实例。这样的对象通常用于控制系统中的几种操作。

想象一下,我们要确保有一个龙母。

为此,我们需要:

  • 用于存储有关龙之母的信息的类
  • 龙母的已保存实例

let INSTANCE = null

class MotherOfDragons {
    constructor(name, dragons) {
        if(!!INSTANCE) return INSTANCE
        this.dragons = dragons
        this.name = name
        this.getMyDragons = this.getMyDragons.bind(this)
        INSTANCE = this
    }

    getMyDragons(){
        console.log(`I'm ${this.name} and my dragons are`, this.dragons)
    }
}

(()=>{
    const dragonMother = new MotherOfDragons('Daenerys Targaryen', [
        'Drogon',
        'Rhaegal',
        'Viserion'
    ])
    const dragonMother2 = new MotherOfDragons('Cercei Targaryen', [
        'Tirion',
        'Jennifer',
        'Goblin'
    ])
    dragonMother.getMyDragons()
    dragonMother2.getMyDragons()
    console.log(dragonMother instanceof MotherOfDragons)
    console.log(dragonMother2 instanceof MotherOfDragons)
    console.log(dragonMother2 === dragonMother)
})()

什么时候使用?


  • 当用于创建对象的资源受到限制时(例如,数据库连接对象)
  • 最好以单例方式建立授权以提高性能。
  • 当您需要创建一个类来配置应用程序时
  • 需要为资源分配创建类时

Github 代码

注意 trans:这是一段有关设计模式的精彩视频

感谢您的关注。

All Articles