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.