Menghasilkan pola desain di ES6 + pada contoh Game of Thrones



Pola desain - cara untuk memecahkan masalah yang paling umum dalam pengembangan perangkat lunak. Pada artikel ini, kita akan melihat pola generatif dengan referensi ke Game of Thrones.

Baca tentang pola struktural di sini .

Pola pembangkitan dirancang untuk bekerja dengan mekanisme untuk membangun objek untuk membuat objek dengan cara yang paling cocok dalam situasi ini.

Pola generatif yang paling umum adalah sebagai berikut:

  • Pabrik (kain)
  • Abstraksi (Abstrak)
  • Konstruktor (Pembangun)
  • Prototipe (Prototipe)
  • Singleton (Singleton)

Pabrik


Sebuah pabrik adalah pola yang menggunakan apa yang disebut metode pabrik untuk membuat objek tanpa perlu menentukan kelas objek yang dibuat. Apa artinya ini?

Bayangkan kita ingin bisa menciptakan tentara. Para prajurit ini bisa dari rumah Targaryen, atau dari rumah Lannister.

Untuk ini kita perlu:

  • Antarmuka untuk mendefinisikan tentara
  • Kelas untuk setiap jenis prajurit untuk memberdayakan setiap rumah
  • Kelas untuk meminta penciptaan seorang prajurit baru, terlepas dari rumah tempat dia berada

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())
})()

Kapan itu digunakan?


  • ,
  • ,


Penafian: Template abstrak berdasarkan objek. Sangat sulit untuk digunakan dalam pemrograman fungsional.

Template ini memungkinkan Anda untuk merangkum sekelompok pabrik individu yang melakukan tugas serupa, tanpa perlu mendefinisikan kelas-kelas tertentu. Dalam penggunaan standar, perangkat lunak klien membuat implementasi spesifik dari pabrik abstrak dan kemudian menggunakan antarmuka pabrik umum untuk membuat objek tertentu sebagai bagian dari sistem tunggal. Klien tidak tahu (atau tidak masalah baginya) objek spesifik apa yang ia terima dari setiap pabrik internal, karena antarmuka umum digunakan untuk ini.

Bayangkan kita ingin mengelola setiap rumah secara individual. Setiap rumah harus memiliki kesempatan untuk menentukan pewaris takhta dan kekasihnya.

Untuk ini kita perlu:

  • ,

//  
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()
})()

?


  • ,
  • ,


Tujuan perancang adalah untuk memisahkan objek yang kompleks dari representasinya. Dengan kompleksitas objek, template ini memungkinkan Anda untuk memisahkan proses membuat objek baru melalui objek lain (konstruktor).

Bayangkan kita ingin membuat armada untuk setiap rumah. Setiap keluarga akan memiliki sejumlah kapal dan prajurit tertentu. Untuk memfasilitasi pembuatan, kita harus dapat memanggil metode makeNavy, yang secara otomatis akan membuat semua yang kita butuhkan melalui pengaturan.

Untuk ini kita perlu:

  • Kelas untuk membuat armada
  • Antarmuka untuk definisi konstruktor
  • Kelas yang bertanggung jawab untuk menciptakan benda-benda tentara kita
  • Kelas yang bertanggung jawab untuk menciptakan tentara dan kapal

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)
})()

Kapan itu digunakan?


  • Ketika proses membuat objek sangat kompleks, itu melibatkan sejumlah besar parameter wajib dan opsional
  • Ketika peningkatan jumlah parameter konstruktor mengarah ke peningkatan jumlah desainer
  • Ketika klien mengharapkan tampilan berbeda untuk objek yang dibangun

Prototipe


Prototipe memungkinkan Anda untuk menentukan jenis objek yang dibuat melalui pewarisan prototipe dan membuat objek baru menggunakan skema objek yang ada. Ini meningkatkan kinerja dan meminimalkan kehilangan memori.

Bayangkan kita ingin menciptakan pasukan pejalan kaki putih. Kami tidak memiliki persyaratan khusus untuk pasukan ini. Kami hanya ingin banyak dari mereka, bahwa mereka memiliki karakteristik yang sama dan bahwa mereka tidak memakan banyak ruang memori.

Untuk ini kita perlu:

  • Kelas untuk menyimpan informasi tentang pejalan kaki putih
  • Metode untuk kloning contoh mengembalikan metode yang sama

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())
    }
})()

Keuntungan dan kerugian dari prototipe


Pro:

  • Membantu menghemat biaya, waktu, dan produktivitas dengan menghilangkan keharusan menggunakan operator baru untuk membuat objek baru
  • Mengurangi kompleksitas menginisialisasi objek: setiap kelas menggunakan metode kloning sendiri
  • Tidak perlu mengklasifikasikan dan membuat banyak subclass untuk menginisialisasi objek seperti ketika menggunakan templat abstrak
  • Meningkatkan fleksibilitas sistem dengan membuat objek baru dengan mengubah beberapa properti objek yang disalin

Minus:

  • Mengkloning objek kompleks dengan referensi melingkar adalah tugas yang tidak sepele

Singleton


Singleton memungkinkan Anda untuk memastikan bahwa objek yang dibuat adalah satu-satunya instance dari kelas tertentu. Objek seperti itu biasanya digunakan untuk mengendalikan beberapa operasi dalam sistem.

Bayangkan kita ingin memastikan memiliki satu Ibu Naga.

Untuk ini kita perlu:

  • Kelas untuk menyimpan informasi tentang Bunda Naga
  • Contoh tersimpan dari Mother Dragon

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)
})()

Kapan itu digunakan?


  • Ketika sumber daya yang digunakan untuk membuat objek terbatas (misalnya, objek koneksi database)
  • Merupakan praktik yang baik untuk membangun otorisasi dengan orang tunggal untuk meningkatkan kinerja.
  • Ketika Anda perlu membuat kelas untuk mengkonfigurasi aplikasi
  • Ketika Anda perlu membuat kelas untuk alokasi sumber daya

Kode github .

Catatan trans: ini adalah video yang bagus tentang pola desain.

Terima kasih atas perhatian Anda.

All Articles