توليد أنماط التصميم في ES6 + على سبيل المثال من Game of Thrones



أنماط التصميم - طرق لحل المشاكل الأكثر شيوعًا في تطوير البرمجيات. في هذه المقالة ، سنلقي نظرة على الأنماط التوليدية مع إشارات إلى Game of Thrones.

اقرأ عن الأنماط الهيكلية هنا .

تم تصميم أنماط التوليد للعمل مع آليات بناء الكائنات من أجل إنشاء كائن بالطريقة الأنسب في هذه الحالة.

الأنماط التوليدية الأكثر شيوعًا هي كما يلي:

  • مصنع (قماش)
  • التجريد (الملخص)
  • منشئ (منشئ)
  • النموذج الأولي (النموذج الأولي)
  • Singleton (Singleton)

مصنع


المصنع هو نمط يستخدم ما يسمى أساليب المصنع لإنشاء كائنات دون الحاجة إلى تحديد فئة الكائن الذي تم إنشاؤه. ماذا يعني هذا؟

تخيل أننا نريد أن نكون قادرين على إنشاء جنود. يمكن أن يكون هؤلاء الجنود إما من منزل Targaryen ، أو من منزل Lannister.

لهذا نحن بحاجة إلى:

  • واجهة لتحديد الجنود
  • صف لكل نوع من الجنود لتمكين كل منزل
  • الفصل لطلب إنشاء جندي جديد ، بغض النظر عن المنزل الذي ينتمي إليه

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 بالتأكد من أن الكائن الذي تم إنشاؤه هو المثيل الوحيد لفئة معينة. يستخدم هذا الكائن عادة للتحكم في العديد من العمليات في النظام.

تخيل أننا نريد التأكد من وجود أم تنين واحدة.

لهذا نحن بحاجة إلى:

  • فصل لتخزين المعلومات حول أم التنانين
  • نسخة محفوظة من 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)
})()

متى يتم استخدامه؟


  • عندما تكون الموارد المستخدمة لإنشاء الكائن محدودة (على سبيل المثال ، كائنات اتصال قاعدة البيانات)
  • من الممارسات الجيدة إنشاء تفويض باستخدام وحدة فردية لتحسين الأداء.
  • عندما تحتاج إلى إنشاء فئة لتكوين التطبيق
  • عندما تحتاج إلى إنشاء فئة لتخصيص الموارد

كود جيثب .

ملحوظة العابرة: هنا فيديو رائع عن أنماط التصميم.

شكرآ لك على أهتمامك.

All Articles