Flyweight design pattern


السلام عليكم و رحمه الله تعالى و بركاته

هذا الموضوع يعتمد على ماتم شرحه فى سلسله جافاسكربت الموجهه بالكائنات .

مقدمه

نمط التصميم Flyweight -وزن الذبابه- مفيد جدا فى المواقف التى يتم فيها انشاء عدد كبير جدا من الكائنات من نفس الصنف و بذلك يؤدى إلى مشاكل فى ذاكره التطبيق ، حيث يقلل نمط التصميم Flyweight عدد الكائنات التى يتم انشاءها إلى كائن واحد – او اقل عدد ممكن – و بذلك ستزداد كفاءه التطبيق بطريقه ملحوظه .

تركيب نمط التصميم Flyweight

نمط التصميم Flyweight يستخدم لتقليل عدد الكائنات التى تحتاجها فى تطبيقك ، يتم ذلك عن طريق تقسيم ال internal state للكائن إلى تصنيفين ، الاول intrinsic data و الثانى extrinsic data . النوع الاول من البيانات Intrinsic هو الذى يتم استخدامه بواسطه الوظائف الداخليه للصنف و لايمكن للوظائف ان تعمل جيدا بدون هذه البيانات ،  اما البيانات من نوع extrinsic هى البيانات التى يكمن ازالتها من الصنف و تخزينها خارجه ، هى التى بدورها تختلف من كائن لاخر . يمكننا نمط التصميم Flyweight من استبدال جميع الكائنات التى لها نفس البيانات ال intrinsic بكائن واحد فقط  .

Factory بدلا من constructor

بدلا من إستخدام constructor عادى ، سنستخدم نمط التصميم Factory لتوليد كائنات جديده ، إذا كان هناك كائن قد تم انشاءه من قبل له نفس البيانات ال intrinsic فسيقوم ال factory بإرجاعه ، اما اذا لم يكن هناك كائن تم انشاءه من قبل له هذه البيانات ال intrinsic فإن ال factory سيقوم بإنشاء كان جديد و تخزينه ، كما سيتم انشاء ايضا كائن مدير manager object يقوم بحفظ البيانات من نوع extrinsic ، حيق عند استدعاء اى من وظائف الكائن فإن الكائن المدير سيقوم بتمرير هذه البيانات ال extrinsic كعبارات لتلك الوظائف .

مثال Car Registerations

تخيل انك تقوم ببرمجه نظام يمثل سيارت المدينه ، بحيث تريد تخزين بيانات كل سياره مثل موديل السياره و الصانع و السنه ، و تريد تخزين بيانات ملكيه السياره مثل الإسم و رقم البطاقه و تاريخ التجديد ، من الطبيعى ان تمثل كا سياره بكائن من نوع Car ، الكود التالى يوضح الصنف Car بدون إستخدام نمط التصميم Flyweight :

/* Car function constructor, unoptimized */
var Car = function(make, model, year, owner, tag, renewDate){
    this.make=make;
    this.model=model;
    this.year=year;
    this.owner=owner;
    this.tag=tag;
    this.renewDate = renewDate;
}
Car.prototype = {
    getMake:function(){
        return this.make;
    },
    getModel:function(){
        return this.model;
    },
    getYear:function(){
        return this.year;
    },
    transferOwnership:function(newOwner, newTag, newRenewDate){
        this.owner = newOwner;
        this.tag = newTag;
        this.renewDate = newRenewDate;
    },
    renewRegisteration:function(newRenewDate){
        this.renewDate = newRenewDate;
    },
    isRegisterationCurrent:function(){
    var today = new Date();
    return today.getTime() < Date.parse(this.renewDate);
    }
};

هذا الصنف سيعمل جيدا ، لكن ستظهر المشاكل يوميا بزياده عدد السيارات التى يتم تسجيلها ، بفرض انك تقوم بتسجيل 1000 سياره سيؤدى ذلك إلى انشاء 1000 كائن من نوع Car ، و سيؤدى ذلك إلى كارثه فى اداء التطبيق ، الحل فى إستخدام نمط التصميم Flyweight لتقليل عدد الكائنات التى يتم انشاءها من الصنف Car إللى اقل عدد ممكن ، اول خطوه هى تقسيم البيانات او العبارت التى تمرر للصنف Car إلى intrinsic و extrinsic .

Intrinsic و Extrinsic

فى هذا المثال سيتم اعتبار الmodel و ال make و ال year البيانات ال intrinsic المميزه لكل سياره ، هذا يعنى انه اذا امتلك 1000 شخص سياره ماركه Mercedes مدويل S-class سنه 2009 ، فإنه سيتم انشاء كائن واحد فقط من نوع Car  يمثل هذه السياره ، اما البيانات التى تتعلق بملكيه السيارت سيبتم حفظها فى الكائن المدير manager object لاحقا ، هكذا سيبدوا الكود الخاص بالصنف Car بعد محو ال extrinsic data منه :

/* Car function constructor, optimized as flyweight */
var Car = function(make, model, year){
    this.make=make;
    this.model=model;
    this.year=year;
};
Car.prototype = {
    getMake:function(){
        return this.make;
    },
    getModel:function(){
        return this.model;
    },
    getYear:function(){
        return this.year;
    }
}

كما ترى تم محو كل البيانات التى تتعلق بملكيها السياره extrinsic data من ال function constructor و محو الوظائف المتعلقه بها أيضا ، الان جاء دور ال Factory الذى سيقوم ببناء الكائنات من الصنف Car .

انشاء الكائنات بإستخدام نمط التصميم Factory

دور ال Factory هنا بسيط جدا ، سيقوم بفحص هل تم انشاء سياره بنفس المواصفات -make,model,year – من قبل ام لا ، اذا تم انشاءها سيتم ارجاعها ، اما اذا لم يتم انشائها سيتم انشاء سياره جديده بهذه المواصفات و يخزنها للإستخدام لاحقا ، و هذا ال factory سيؤكد على ان كل سياره يتم انشائها ذات مواصفات intrinsic فريده ، كما يوضح الكود البسيط التالى :

/* CarFactory Singleton */
var CarFactory = (function(){
    var createdCars = {};
    return {
        createCar:function(make, model, year){
            // if created before, return it.
            if(createdCars[ make + "-" + model + "-" + year ]){
                return createdCars[ make + "-" + model + "-" + year ];
            }
            // otherwise create new car, save it, return it.
            else{
                var car = new Car(make, model, year);
                createdCars[ make + "-" + model + "-" + year ] = car;
                return car;
            }
        }
    };
})();

تخزين ال extrinsic data فى object manager

اخر كائن سيتم انشاءه لإنهاء عمليه التحسينات optimization هو الكائن المدير manager object الذى سيحفظ البيانات ال extrinsic التى تم محوها من الصنف Car ، و الوظائف المتعلقه بهذه البيانات ال extrinsic ، سنستخدم نمط التصميم Singleton لإنشاء ال manager object كما يوضح الكود البسيط التالى :

var CarRecordManager = (function(){
    var carRecordDatabase = {};
    return {
        // add new car in the system
        addCarRecord:function(make, model, year, owner, tag, renewDate){
            var car = CarFactory.createCar(make, model, year);
            carRecordDatabase[tag]{
                owner:owner,
                renewDate:renewDate,
                car:car,
            };
        },
        // methods previously contained in Car Calss
        transferOwnership:function(tag, newOwner, newTag, newRenewDate){
            var record = carRecordDatebase[tag];
            record.owner = newOwner;
            record.tag = newTag;
            recoed.renewDate = newRenewDate;
        },
        renewRegistration:function(tag, newRenewDate){
            carRecordDatabase[tag].renewDate = newRenewDate;
        },
        isRegsiterationCurrent:function(tag){
            var today = new Date();
            var renewDate = carRecordDatabase[tag].renewDate;
            return today.getTime() < Date.pares(renewDate);
        }
    };
})();

كل ال extrinisc data تم تخزينها فى الخاصيه الخاصه carRedcordDatabase بالإضافه إلى الكائن car المتعلق بهذه البيانات ، بالطبع تخزين البيانات فى object literal افضل من عدد غير محدود من الكائنات ، كما ترى التحسينات قد أدت إلى زياده تعقيد الكود ، بدلا من صنف واحد لأنشاء الكائنات من نوع Car ، الان لدينا صنف Car و factory لإنشاء الكائنات من نوع Car و singleton لحفظ البيانات ال extrinsic ، لكن اذا وازنت هذا التعقيد مع التحسينات التى ستطرأ على كفاءه التطبيق ، فإن الكفاءه هى التى ستربح .

هذا الموضوع هو تلخيص الفصل الثالث عشر من كتاب APRESS: Pro JavaScript design patterns إرجع إليه للمزيد ، حيث قام الكتاب بشرح مثالين ، الاول قامووا فيه بعمل تقويم Calendar يحتوى على صنف Year و صنف اخر Month و صنف اخر Day من نوع flyweight بدلا من انشاء 30 كائن من نوع Day لكل شهر ، و 365 كائن Day لكل سنه ، حيث أدى هذا التحسين إلى تقليل الكائنات إلى كائن واحد فقط😀 ، المثال التالى Tooltip و هو التلميح الذى يظهر عندما تقف بالماوس على عنصر ما ، حيث يقوم بإظهار نص يصف هذا العنصر ، و مادام ان ال tooltip تظهر مره واحده ، اى انه لايمكن ظهور اكثر من واحده فى نفس الوقت ، فهذا يؤهلها لأن تكون flyweight ، بدلا من انشاء 1000 كائن Tooltip ل 1000 عنصر ، يمكننا انشاء كائن واحد فقط tooltip و فصل البيانات ال intrinsic و ال extrinsic كما وضحت فى مثال ال Car registeration ، بالطبع لا يمكننى شرح هذه الامثله هنا لأنها طويله جدا .

خارج النص :  انتهى john resig مطور اطار عمل jQuery من 12 فصل فى كتابه الجديد Manning: Secrets of the JavaScript Ninja أسرار نينجا الجافاسكربت ، طبعا الكتاب موجه للمستوى المتقدم ، فى انتظار انتهاء الكتاب ، احتمال اتوقف عن التدوين بعد انتهاء سلسله انماط تصميم جافاسكربت عشان الامتحانات ، و احتمال اتكلم عن البرمجه الوظيفيه بالجافاسكربت🙂 كل كم يوم بدلا من التوقف عن التدوين ، البرمجه الوظيفيه شيقه جداااااا ، ادعولى بالتوفيق .

الأوسمة: , , , , ,

3 تعليقات to “Flyweight design pattern”

  1. almhajer Says:

    لافظ فوك جزاك الله عنا الف الف الف خير
    موضوع هذا يستحق التمعن لانه ادى لا ضغط الكود بشكل كبير وادعى الى فصل الكود الكبير المحشور الى كود مركب وبحسب استعابي لهذا المفهوم يعتبر مفهوم الملاصقة والمزاوجة والانعكاس اساس لهذه النظرية بحيث ادى الى عدم تلاصق الكود ودمجه مماناعكس على الكود بشكل قوي جدا بارك الله فيك وشكرا جزيلا

  2. مجنون الجافا Says:

    عفو هذا الدرس موجود في كتب pattern

    ليس من شرحك بل من الترجمتك

    ارجو حفظ الحقوق

    مجنون الجافا

أضف تعليقاً

إملأ الحقول أدناه بالمعلومات المناسبة أو إضغط على إحدى الأيقونات لتسجيل الدخول:

WordPress.com Logo

أنت تعلق بإستخدام حساب WordPress.com. تسجيل خروج   / تغيير )

صورة تويتر

أنت تعلق بإستخدام حساب Twitter. تسجيل خروج   / تغيير )

Facebook photo

أنت تعلق بإستخدام حساب Facebook. تسجيل خروج   / تغيير )

Google+ photo

أنت تعلق بإستخدام حساب Google+. تسجيل خروج   / تغيير )

Connecting to %s


%d مدونون معجبون بهذه: