Generieren von Entwurfsmustern in ES6 + am Beispiel des Game of Thrones



Entwurfsmuster - Möglichkeiten zur Lösung der häufigsten Probleme in der Softwareentwicklung. In diesem Artikel werden wir generative Muster mit Verweisen auf das Game of Thrones betrachten.

Lesen Sie mehr über Strukturmuster hier .

Das Generieren von Mustern soll mit Mechanismen zum Konstruieren von Objekten arbeiten, um in dieser Situation ein Objekt auf die am besten geeignete Weise zu erstellen.

Die häufigsten generativen Muster sind wie folgt:

  • Fabrik (Stoff)
  • Abstraktion (Zusammenfassung)
  • Konstruktor (Baumeister)
  • Prototyp (Prototyp)
  • Singleton (Singleton)

Fabrik


Eine Factory ist ein Muster, das mithilfe der sogenannten Factory-Methoden Objekte erstellt, ohne die Klasse des erstellten Objekts bestimmen zu müssen. Was bedeutet das?

Stellen Sie sich vor, wir wollen Soldaten erschaffen können. Diese Soldaten können entweder aus dem Targaryen-Haus oder aus dem Lannister-Haus stammen.

Dafür brauchen wir:

  • Schnittstelle zur Definition von Soldaten
  • Eine Klasse für jeden Soldatentyp, um jedes Haus zu stärken
  • Klasse, um die Schaffung eines neuen Soldaten zu beantragen, unabhängig von dem Haus, zu dem er gehört

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

Wann wird es verwendet?


  • ,
  • ,


Haftungsausschluss: Eine abstrakte Vorlage, die auf Objekten basiert. Die Verwendung in der funktionalen Programmierung ist äußerst schwierig.

Mit dieser Vorlage können Sie eine Gruppe einzelner Fabriken kapseln, die ähnliche Aufgaben ausführen, ohne bestimmte Klassen definieren zu müssen. Bei der Standardverwendung erstellt die Client-Software eine bestimmte Implementierung der abstrakten Factory und verwendet dann die allgemeine Factory-Schnittstelle, um bestimmte Objekte als Teil eines einzelnen Systems zu erstellen. Der Kunde weiß nicht (oder ist ihm egal), welche spezifischen Objekte er von jeder internen Fabrik erhält, da hierfür eine gemeinsame Schnittstelle verwendet wird.

Stellen Sie sich vor, wir möchten jedes Haus einzeln verwalten. Jedes Haus sollte die Möglichkeit haben, den Thronfolger und seinen Geliebten zu bestimmen.

Dafür brauchen wir:

  • ,

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

?


  • ,
  • ,


Der Zweck des Designers besteht darin, ein komplexes Objekt von seinen Darstellungen zu trennen. Aufgrund der Komplexität des Objekts können Sie mit dieser Vorlage den Prozess des Erstellens eines neuen Objekts durch ein anderes Objekt (Konstruktor) trennen.

Stellen Sie sich vor, wir möchten für jedes Haus eine Flotte erstellen. Jede Familie wird eine bestimmte Anzahl von Schiffen und Kriegern haben. Um die Erstellung zu erleichtern, sollten wir in der Lage sein, die Methode makeNavy aufzurufen, die automatisch alles erstellt, was wir über die Einstellungen benötigen.

Dafür brauchen wir:

  • Klasse zum Erstellen einer Flotte
  • Schnittstelle zur Konstruktordefinition
  • Die Klasse, die für die Erstellung der Objekte unserer Armee verantwortlich ist
  • Klassen, die für die Schaffung von Soldaten und Schiffen verantwortlich sind

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

Wann wird es verwendet?


  • Wenn das Erstellen eines Objekts sehr komplex ist, sind eine Vielzahl von obligatorischen und optionalen Parametern erforderlich
  • Wenn eine Erhöhung der Anzahl der Konstruktorparameter zu einer Erhöhung der Anzahl der Designer führt
  • Wenn der Client unterschiedliche Ansichten für das erstellte Objekt erwartet

Prototyp


Mit dem Prototyp können Sie die Arten von Objekten bestimmen, die durch die Vererbung von Prototypen erstellt wurden, und neue Objekte mithilfe des Schemas eines vorhandenen Objekts erstellen. Dies verbessert die Leistung und minimiert den Speicherverlust.

Stellen Sie sich vor, wir wollen eine Armee weißer Wanderer aufbauen. Wir haben keine besonderen Anforderungen an diese Armee. Wir wollen nur viele von ihnen, dass sie die gleichen Eigenschaften haben und nicht viel Speicherplatz beanspruchen.

Dafür brauchen wir:

  • Klasse zum Speichern von Informationen über weiße Wanderer
  • Methode zum Klonen einer Instanz, die dieselbe Methode zurückgibt

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

Vor- und Nachteile des Prototyps


Vorteile:

  • Spart Kosten, Zeit und Produktivität, da kein neuer Operator zum Erstellen neuer Objekte erforderlich ist
  • Reduziert die Komplexität der Initialisierung eines Objekts: Jede Klasse verwendet ihre eigene Klonmethode
  • Es ist nicht erforderlich, viele Unterklassen zu klassifizieren und zu erstellen, um Objekte wie bei Verwendung einer abstrakten Vorlage zu initialisieren
  • Erhöht die Systemflexibilität durch Erstellen neuer Objekte durch Ändern einiger Eigenschaften des kopierten Objekts

Minuspunkte:

  • Das Klonen komplexer Objekte mit Zirkelverweisen ist keine triviale Aufgabe

Singleton


Mit Singleton können Sie sicherstellen, dass das erstellte Objekt die einzige Instanz einer bestimmten Klasse ist. Ein solches Objekt wird normalerweise verwendet, um mehrere Operationen im System zu steuern.

Stellen Sie sich vor, wir möchten sicher sein, eine einzige Drachenmutter zu haben.

Dafür brauchen wir:

  • Klasse zum Speichern von Informationen über Mutter der Drachen
  • Gespeicherte Instanz von Dragon Mother

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

Wann wird es verwendet?


  • Wenn die zum Erstellen des Objekts verwendeten Ressourcen begrenzt sind (z. B. Datenbankverbindungsobjekte)
  • Es wird empfohlen, eine Autorisierung mit einem Singleton zu erstellen, um die Leistung zu verbessern.
  • Wenn Sie eine Klasse erstellen müssen, um die Anwendung zu konfigurieren
  • Wenn Sie eine Klasse für die Ressourcenzuweisung erstellen müssen

Github- Code .

Hinweis trans: hier ist ein tolles Video über Designmuster.

Vielen Dank für Ihre Aufmerksamkeit.

All Articles