3. الگوهاي طراحي
۳
به نام خدا
سخني با دوستان
اين چند صفحه، مجموعه اي از پست هاي گسسته من در چند سال قبل درباره الگوهاي طراحي در و بلاگ مهندسي نرم افزار
بو د .كه به پيشنهاد دوستان به صورت يك فايل يكپارچه براي دانلود قرار مي دهم . من شخصاً خيلي علاقه داشتم كه حداقل در
وبلاگ، به بررسي ۲۳ الگوي كلاسيك طراحي نرم افزار بپردازبم . ولي هرگز فرصت كاملي براي اينكار به نحو ي كه در ذهن
داشتم بوجود نيامد . پس در نهايت تصم يم گرفتم همين مطالب را براي به اشتراك گذاشتن در ق الب يك فايل آماده كنم . شايد با
نظرات و راهنمايي شما دوستان اين مجموعه ناقص و پر عيب را به مرور اصلاح و تكميل كنيم . لطفاً دوستان اگر نظر و ديدگاهي
براي كامل تر كردن و اصلاح اين مجموعه دارن د، مي توانند با ايميل و وبلاگهاي زير با من در ارتباط باشند . تا به كمك هم به
مرور اين مجموعه را كامل تر كنيم .
behrouzlo@yahoo.com Email :
Http://ooa.blogfa.com Weblogs :
Http://ooad.wordpress.com
5. الگوهاي طراحي
۵
اشياء
شما دنيا را چگونه مي بينيد ؟
شما دنيا را چگونه مي بينيد ؟ جواب اين سوال بستگي به ذهنيت قبلي شما دارد . يك دانشمند ممكن است دنيا را يه صورت
ساختارهاي مولكولي ببيند . يك نفاش دنيا را در قالب اشكال و رنگ ها ببيند . و بعضي ها دنيا را به صورت مجموعه اي از اشياء و
مواد ببينند . شايد اولين چيزي كه به ذهن شما خطور كند اين باشد كه اين سوال چه ارتباطي با متدولوژي شي گرا دارد ؟ اما اين
نوع نگاه مهم است زيرا يك مهندس نرم افزار و برنامه نو يس بايد دنيا را در قالب اشياء ببينند تا بتوانند آنها را در قالب برنامه هاي
كامپيوتري شبيه سازي كنند .
يك شي چست ؟
يك شي مي تواند يك موجوديت فيزيكي باشد ، مانند يك كتاب ، يك صندلي . شما مي توانيد يك كتاب را توصيف كنيد ،
آنرا بخوانيد و آنرا بخريد .
باشد ، مانند يك كار يا زمان . با اينكه يك كار (i ntangible ) يك شي مي تو اند يك موجوديت غير فيزيكي و غير قابل لمس
چيزي است كه شما بصورت فيزيكي نمي توانيد آنرا لمس كنيد اما مي توانيد آنرا توصيف كنيد ، روي آن بحث كنيد ، آنرا انجام
بدهيد و تكميل كنيد . هر چيزي كه بتوانيد آن را توصيف كنيد مي تواند به عنوان يك شي در نظر گرفته شود.
يك كتاب ، يك صندلي ، يك كار و هر شي در دنيا واقعي بوسيله دو گروه از خصوصيات مشخصي مي شوند :
صفات ويژگيهاي يك شي را بيان مي كند . در واقع يك صفت يك ويژگي از يك شي است : (a ttributes ) ۱. صفا ت
مانند صفت نام بر اي يك فرد . صفات توصيف كننده يك شي هستند و با استفاده از مقادير صفات مي توان وضعيت
فعلي يك شي را بدست آورد . براي مثال يك فرد مي تواند داراي صفت تاهل باشد كه با استفاده از مقدار اين صفت
مي توان وضعيت تاهل آن فرد را در شرايط فعلي بدست آورد .
ي ك رفتار عملي است كه يك شي توانايي انجام دادن آن را دارد . براي مثال يك شخص مي ( behaviors): ۲. رفتار
تواند راه برود ، بدود ، بنشيند و هزاران كار ديگري كه قادر به انجام دادن آن است كه هر كدام از اين كارها براي آن
شخص يك رفتار محسوب مي شود . يك سوال يك كتاب مي تواند چه رفتاري داشته باشد . آيا يك كتاب قادر به
انجام دادن كاري است تا به عنوان يك رفتار براي آن شي به حساب آيد ؟ شي كتاب در حقيقت قادر به انجام هيچ
كاري نيست . يك ناشر براي انتشار يك كتاب كارهاي مانند ويرايش كتاب ، چاپ كتاب ، توزيع كتاب و در آخر
6. الگوهاي طراحي
۶
فروش كتاب را انجام مي دهد . اين كارها توسط يك نفر بر روي كتاب انجام مي گيرد . متدلوژي شي گرا به ما مي
گويد كه اين رفتارها را به جاي فردي كه اين كارها را انجام مي دهد را به شي كتاب تخصيص بدهيم.
7. الگوهاي طراحي
۷
(Abstract Objects) اشياء انتزاعي
توصيفي از يك شي واقعي بدون در نظر كرفتن جزئيات آن شي اس ت. (A bstract Object ) يك شي انتزاعي
Abstract Object = Real Object – Details
( شي انتزاعي = شي واقعي - جزئيات )
به عنوان مثال ما براي يك شي فرد خصوصياتي مانند نام ، نام خانوادگي ، قد و وزن را در نظر مي گيريم و از بقيه صفات مربوط به
آن صرفنظر مي كنيم .
يك شي انتزاعي مدلي از شي واقعي است . يك شي واقعي همه صفات و رفتارهاي تعريف شده يك شي انتزاعي را دارد همراه با
جزئيات حذف شده از شي انتزاعي . براي مثال شي انتزاعي فرد يك مدل براي يك شخص واقعي است . شي انتزاعي مي گويد كه
يك شخص واقعي بايد يك نام ، نام خانوادگي ، قد و وزن داشته باشد . يك شخص واقعي مقادير مرتبط با اين صفات را مشخص
مي كند . مانند :
نام : بهروز
نام خانوادگي : بختياري
قد : ۱۷۵
وزن : ۶۰
يك نمونه از شي انتزاعي است . شما مي توانيد بگويد كه يك شخص واقعي يك نمونه از فرد (R eal Object ) يك شي واقعي
انتزاعي است .
شي انتزاعي = يك مدل از شي واقعي
شي واقعي = يك نمونه از شي انتزاعي
انتزاعي كردن اشياء واقعي :
8. الگوهاي طراحي
۸
براي مثال شما تصور كنيد كه مي خواهيد با يك فرد تماس بگيريد ، شما براي تماس با آن فرد نياز نداريد كه همه چيز را درباره
او بدانيد و فقط با دانستن نام و شماره تلفن طرف مقابل مي توانيد با او تماس بگيريد . شما مي توانيد نام پدر ، عادات و علايق آن
قرد را بدانيد و تمام اطلاعات دقيق و معتبر باشد ولي براي كاري كه قرار است انجام بدهيد نياز به هيچ يك از اين اطلاعات
نداريد . شما براي انتزاعي كردن يك شي نياز داريد فقط صفات و رفتارهاي را از يك شي داشته باشيد كه براي انجام دادن كاري
كه قرار است انجام بدهيد ضروري هستند و بقيه صفات و رفتارها را بايد حذف كنيد.
9. الگوهاي طراحي
۹
( Class ) كلاس
صفات و رفتارهاي مربوط به شي يك كتاب را در قسمت اول مفاهيم شي گرايي بررسي كرديم، تمامي صفات و رفتارهاي مربوط
به اين شي كتاب را ديگر كتابها نيز دارند پس شما مي توانيد يك مجموعه از قوانين را ايجاد كنيد و براي همه كتابها نيز از آن
استفاده كنيد . مجموعه قوانين را كلاس مي نامند . يك كلاس مجموعه اي از اشياء است .اگر مجموعه اي از اشياء داراي صفات و
ر فتارهاي مشابه باشند، شما مي توانيد اين اشياء را در يك كلاس گروهبندي كنيد .
است كه صفات و رفتارهاي يك شي واقعي را تعريف مي كند . يك كلاس را همانند يك (t emplate ) يك كلاس يك الگو
تعريف مي كند . اگر شما A نيست اما چيزي را شبيه حرف A در نظر بگيريد . قالب شريني حرف A قالب شريني با شكل حرف
بوجود مي آوريد ، اگر شما يك A را بخواهيد ، قالب شريني را بر روي خمير شريني قرار مي دهيد و يك حرف A يك حرف
را بوجود مي آوريد و هر چند بار A ديگر را بخواهيد دوباره قالب را روي خمير قرار مي دهيد و يك حرف ديگر A حرف
ديگر كه بخواهيد مي تو انيد اين فرايند را با همان قالب شريني تكرار كنيد .
پارگراف بالا درباره كلاس ها نيز صادق است . هنگاميكه شما يك شي را به نمايندگي از يك كلاس مي خواهيد ، شما يك نمونه
است همانند هنگاميكه شما قالب شريني را از روي خمير A از آن كلاس را ايجاد مي كنيد . يك نمونه شبيه حرف (i nstance )
بر مي داري د.
هر نمونه شامل همان رفتارها و صفاتي است كه در كلاس تعريف شده اند ، اگر چه هر نمونه يك كپي از صفات را براي خود
دارد.
10. الگوهاي طراحي
۱۰
روابط بين اشياء و كلاس ها
اشياء براي اينكه كاري انجام بدهند نياز دارند با هم كار كنند پس آنها نياز به روشي دارند كه با هم ارتباط برقرار كنند . وقتي كه
يك مشتري بليط هاي را سفارش مي دهد، مشتري بايد يك سفارش ايجاد كند و بليط مورد نظرش را به آن سفارش اضافه كند .
اشياء نرم افزاري كه نماينده مشتري، سفارش، بليط هستند نياز دارند تا رابطه بين اشياء دنيا واقعي را عينا تك رار كنند .
يك ارتباط بين دو كلاس هست . (a ssociation ) رابطه بين دو شي است . يك رابطه (L ink ) يك لين ك
رابطه بين كلاس ها (اشيا ء) به سه شكل متفاوت تقسيم مي شود :
(a ssociation ) ۱. ارتباط
(a ggregation ) ۲. رابطه تجمع
( composition ) ۳. رابطه تركيب
: ( association ) ارتباط
بين دو شي مي باشد . يك شي بطور ساده (p eertopeer)
ساده ترين شكل رابطه، ارتباط مي باشد . كه يك رابطه نظير به نظير
درباره شي ديگر مي داند بهمان طريقي كه يك فرد ممكن است فرد ديگري را بشناشد . يك ارتباط يه يك كلاس امكان مي دهد
تا درباره صفات و رفتارهاي كلاس ديگر بداند .
يك سيستم شي گرا از انواع كلاس ها تشكيل شده است كه از طريق ارسال پيام ها و دريافت پاسخها با يكديگر همكاري دارند .
هنگام اجرا، يك سيستم شي گرا، مملو از نمونه هاي مي شوند كه مطابق نوع كلاس خود مي باشند . جايي كه نمونه هاي كلاس
پيام هاي را به نمونه هاي كلاس دي گر ارسال مي كند يك ارتباط بين آنها بوجود آمده است .
براي مثال كلاس تحويل دار درباره صفات و رفتارهاي كلاس حساب بانكي مي داند و كلاس حساب درباره صفات و عمليات
تحويل دار مي داند . بنابراين اين دو كلاس مي توانند پيغامهايي را به يكديگر ارسال كنند .
:( aggregation ) رابطه تجمع
رابطه تجمع، يك رابطه بين يك واحد كل و جزء است . در رابطه تجمع يك كلاس مي تواند شامل نمونه هاي از كلاس هاي
ديگر نيز باشد . براي مثال يك كلاس ماشين را در نظر بگيريد، كه خود از چندين كلاس ديگر مانند يك كلاس موتور، چندين
كلاس لاستيك و تعدادي كلاس ديگر براي ساير بخش ها تشكيل شده است.
11. الگوهاي طراحي
۱۱
در رابطه تجمع، شي جز به شي كل وابسته نيست . شي كل و جزء در زمانهاي مختلف ايجاد و از بين مي رود يعني ممكن است شي
جزء را ايجاد كنيد بدون اينكه شي كل را يجاد كنيد . براي مثال شي موتور و لاستيك را ايجاد مي كنيد بدون اينكه شي ماشين را
ايجاد كنيد . يا بر عكس ممكن است شي ماشين را با اشياء كه قبلا وجود داشته اند ايجاد كنيم بدون اينكه نياز باشد همزمان با ايجاد
ماشين، آنها را ايجاد كنيم .
براي مثال يك كلاس براي تيم پروژه در نظر بگيريد . و يك كلاس براي كارمندان شركت در نظر بگيريد . تيم پ روژه، از كارمندان
شركت تشكيل شده است . اما ممكن است يك تيم پروژه منحل شود در حاليكه كارمندان به كار خود در شركت ادامه مي دهند .
:( composition ) رابطه تركيب
رابطه تركيب، شبيه رابطه تجمع مي باشد اما با يك تفاو ت:
در رابطه تركيب، چرخه حيات جزء نمي تواند بيش از چرخه حيات كل باشد . به عبارت ديگر شي جزء هيچ وقت نمي تواند بدون
شي كل وجود داشته باشد، شي جزء همزمان با شي كل بوجود مي آيد و همزمان با شي كل از بين مي رود .
براي مثال يك پنجره در سيستم عامل ويندوز را در نظر بگيريد، يك پنجره از چندين شي تشكيل شده است بعنوان م ثال
يك منو و .... زمانيكه يك شي پنجره ايجاد مي شود همزمان با آن تمام دكمه ها ، Close ، Maximize ، Minimize دكمه
و منو ايجاد مي شود . با بستن پنجره تمام اشياء، پنجره، دكمه ها و منو از بين مي روند . امكان ندارد بدون وجود يك شي پنجره
يك شي منو ايجاد شود و به كاربر نمايش داده شود يا با بستن و از بين رفتن شي پنجره، شي منو از بين نرود .
است . در يك رابطه تركيب هنگاميكه ركورد اصلي حذف (c ascading deletion ) رابطه تركيب همان حذف پخش شونده
مي شود تمام ركورد هاي مرتبط با ركورد اصلي حذف مي شوند .
رابطه تركيب، مستلزم چرخه هاي حيات همزمان است، به طوريكه وقتي شي، كل حذف مي شود، اشياء جز نيز حذف مي شو د.
: (G eneralization) رابطه تعميم
شما زمانيكه در يك سوپر ماركت قدم مي زنيد . شما مواد غذايي را بر حسب ويژگهاي آنها در قسمت هاي مختلف يك سوپر
ماركت مشاهده مي كنيد . ميوه ها و سبزيجات در يك قسمت فروشگاه، كوشت در قسمتي ديگر از فروشگاه و خشكبار را در
قسمتي ديگر از فروشگاه پيدا مي كنيد . همه اينها مواد غذايي هستند، اما اينها انواع مختلفي از مواد غذايي هستند .عبارت هاي " تا
يك رابطه تعميم را بين دو كلاس نشان ميدهد .(براي مثال سيب نوعي از ميوه (" Type of " ) " نوعي از " ، (" Kind of " )" حدي
12. الگوهاي طراحي
۱۲
است و ميوه نيز نوعي از غذا است .) در بعضي مواقع عبارت "هست يك " بيانگر رابطه تعميم است . (براي مثال سيب قرمز يك
سيب هست .)
ناميده مي شود .مثال سيب را در نظر بگيريد . سيب نوعي م يوه است پس سيب تمام (i nheritance ) اين نوع رابطه اغلب، وراثت
از ميوه است زيرا آن تمام ويژگيهاي ميوه را به ارث (s pecialization ) ويژگيهاي يك ميوه را به ارث مي برد .همچنان سيب
مي برد و همچنين سيب بعضي از ويژگيها را دارد كه فقط متعلق به سيب مي باشد و سيب را از ديگر ميوه ها متمايز مي كند . پس
از هندوانه، سيب، هلو و همه ديگر اشياء است كه در اين گروه قرار (g eneralization ) مي توان گفت كه ميوه يك تعميم
دارند .
وراثت در سيستم هاي شي گرا همانند به ارث بردن مشخصات رفتاري و بدني از والدينتان است . مشخصات رفتاري و بدني، همان
صفات و رفتارهاي يك كلاس هستند كه يك كلاس از كلاس ديگر مي تواند به ارث ببرد .وراثت زيستي يك مدل سلسله مراتبي
بوجود مي آورد كه شما را قادر مي سازد با دنبال كردن اين سلسله مراتب و بالا رفتن در آن اجداد خودتان را بشناس د. در سيستم
هاي شي گرا نيز دقيقا به ابن صورت است كه شما مي توانيد با دنبال كردن اين ر ابطه، كلاس مولد كلاس جاري را بدست آوري د.
سيب قرمز يك سيب است . پس كلاس مو لد سيب قرمز ، كلاس سيب است . سيب نوعي ميوه است . پس كلاس مولد سيب،
است . ( s uper class ) است . ميوه يك سوپر كلا س (s ub class ) كلاس ميوه است . سيب يك زير كلا س
سوپر كلاس : يك سوپر كلاس، كلاسي است كه داراي ويژگيهاي است كه بين دو يا چند كلاس مشترك است و آنها را با آن
كلاس ها به اشتراك گذاشته است . سيب يك سوپر كلاس براي سيب قرمز اس ت. همه صفات و رفتارهاي مشترك بين سيب قرمز
و سيب، در كلاس سيب تعريف شده است و سيب قرمز از آن صفات و رفتارها استفاده مي كند .
زير كلاس : يك زير كلاس، كلاسي است كه داراي ويژگيهاي است كه منحصر به آن كلاس مي باشد همراه با ويژگيهاي كه
در يك سوپر كلاس تعريف شده است و آنها را از آن سوپر كلاس به ارث مي بر د. يك كلاس مي تواند هم سوپر كلاس باشد و
هم يك زير كلاس . كلاس سيب يك سوپر كلاس ب راي كلاس سيب قرمز است و يك زير كلاس براي كلاس ميوه اس ت.
كلاس انتزاعي، كلاسي است كه نمي تواند نمونه اي داشته باشد . يك كلاس : (a bstract class ) كلاس انتزاع ي
انتزاعي بايد توسط يك كلاس به ارث برده شود تا از صفات و رفتارهاي آن استفاده شود.
13. الگوهاي طراحي
۱۳
: (P olymorphism ) چند شكلي
قابليت دارد كه شكل هاي مختلف به خود بگيرد .منظور از شي (t hing) چند شكلي به طور تكنيكي بدين معني است كه يك ش ي
در جمله بالا يك متد مي باشد . و منظور از شكل، رفتاري است كه توسط آن متد انجام مي شود .چند شكلي يعني اينكه يك متد
مي تواند داراي رفتار هاي مختلف باشد .
ممكن است در ابتدا مفهوم چند شكلي گيج كننده باشد . اما اين سر در گمي با يك مثال از دنيا واقعي مي تواند، بطور كامل از بين
برود . كليد روشن و خاموش كردن كامپيوتر خود را در نظر بگيريد، زمانيكه شما بخواهيد كامپيوتر خود را روشن كنيد دكمه را
فشار مي دهيد و كامپيوتر روشن مي شو د. زمانيكه مي خواهيد كامپيوتر خود را خاموش كنيد، دكمه را فشار مي دهيد و كامپيوتر
خاموش مي شود .
در مثال بالا متد فشار دادن كليد در شرايط مختلف، عمليات خاصي را انجام مي دهد . اين يعني چند شكلي . يك مثال ديگر را
بررسي مي كنيم، تصور كن يد كه در يك فروشگاه به كالاها تخفيف داده مي شود . اما براي انواع مختلف كالاها، نخفيف به روش
متقاوتي محاسبه مي شود . در اين حالت ما يك متد تخفيف داريم اما در پياده سازي نسبت به نوع كالا، عمليات متفاوتي را براي
محاسبه تخفيف خواهيم داشت .
پياده سازي مي شود . تصور كنيد كه يك سوپر كلاس به (G eneralization ) چند شكلي در اغلب موارد از طريق رابطه تعميم
نام كالا داريم كه داراي متدي به نام تخفيف مي باشد . كلاس هاي مواد غذايي، پوشاك،كتاب و ... را در نظر بگيريد .اين كلاس
ها،زير كلاس، كلاس كالا مي باشند . كه صفات و متد هاي آن را به ارث برده اند .اما نحوه محاسبه تخفيف در كلاس هاي مختلف
با همديگر متفاوت مي باشد .در اين حالت در هر زير كلاس متد تخفيف نسبت به عملياتي كه بايد انجام بدهد تا تخفيف را محاسبه
كند بايد بازنويسي شود اما با همان نام قبلي تخفيف .متد تخفيف در كلاس هاي مختلف معرف رف تار جداگانه اي هست اما تخت
همان نام قبلي تخفيف.
14. الگوهاي طراحي
۱۴
:( E ncapsulation ) نهان سازي
نهان سازي يك از مفاهيم شي گرايي است كه شما بصورت مكرر در زندگي روزانه از آن استفاده مي كنيد . آيا شما پو ل،
گواهينامه رانندگي و كارت اعتباري خود را در كيف پو لتان قرار مي دهيد ؟ آيا شما خودكار ها، كاغذها و كتاب هاي خود را در
كيف تان قرار مي دهيد و به مدرسه مي بريد؟ اگر اينگونه باشد پس شما از نهان سازي استفاده مي كنيد . نهان سازي به معني قرار
دادن چيزهاي مرتبط به هم در داخل يك شي جديد است .براي مثال يك حساب بانكي شامل : شمار ه حساب، نام مشتري، آدرس
مشتري، نوع حساب و موجودي مشتري مي باشد . همچنين براي يك حساب بانكي رفتارهاي مانند باز كردن حساب، بستن حساب،
برداشت از حساب و واريز به حساب وجود دارد . شما اين اطلاعات را باهم در داخل يك شي حساب پنهان مي كنيد .
ائده اصلي كه نهان سازي ا رائه مي دهد اين است كه رفتار يك شي بايد تا حد ممكن دور از ديد كاربر باشد . به عبارت ديگر تا
زماني كه لازم نباشد، كاربر نبايد متوجه شود كه يك شي چگونه درخواست هاي او را انجام مي دهد .
استفاده از يك شي :
تصور كنيد كه شما مي خواهيد به يك فرد رانندگي ياد بده يد براي اينكار شما يك سري از اطلاعات ضروري كه بايد آن فرد
بداند را مشخص مي كنيد .به عنوان نمونه شما اطلاعاتي درباره ترمز ، دنده ، فرمان و آيينه را به او آموزش مي دهيد . اما آيا شما
درباره نحوه كاركرد موتور ، نحوه عملكرد سيستم ترمز نيز مطالبي را به او ياد مي دهيد؟ نه، زيرا او نيازي ندارد كه براي رانندگي
كردن بداند كه عملكرد داخلي ماشين چگونه است .
ناميده مي (I nterface ) اطلاعاتي كه ماشين در معرض نمايش قرار مي دهد تا يك فرد بتواند از آن استفاده كند واسط ماشين
شود . يك واسط راهي است تا شما با يك شي ارتباط برقرار كنيد براي آنكه شما مي خواهيد از رفتارهاي آن شي استفاده كنيد .
براي مثال هنگاميكه شما پاي خود را روي پدال گاز ماشين قرار مي دهيد ، شما به او مي گوييد كه سريعتر حركت كند .
يك واسط همچنين به شما اجازه مي دهد تا به اطلاعاتي از آن شي دسترسي پيدا كنيد . براي مثال واسط كيلو متر شمار مقدار
مسيري كه به كيلومتر توسط آن ماشين طي شده است را نمايش مي دهد .
آيا يك واسط به تنهايي كاري را انجام مي دهد؟ نه، يك واسط به تنهايي كاري را انجام نمي ده د. يك واسط بدون پياده سازي
هيچ كاري را انجام نمي دهد . شما مي توانيد با يك شي ارتباط برقرار كنيد اما آن هيچ كاري انجام نمي (i mplementation )
15. الگوهاي طراحي
۱۵
دهد . براي مثال شما يك كنترل از راه دور تلويزيون را در نظر بگيريد اگر مدار داخلي اين شي پياده سازي نشده باشد ما با فشار
دادن هر كدام از كليد ها هيچ عكس العملي را مشاهده نخواهيم كرد .
براي اينكه يك شي بتو اند وظايف خود را انجام دهد، شما نياز داريد كه مكانيزمهاي را فراهم كنيد كه به عملكردهاي واسط
جواب بدهد . براي مثال هنگامي كه شما پدال گاز را فشار مي دهيد، رفتاري كه پشت واسط قرار دارد ولي كاربر آنرا مشاهده نمي
كند باعث خواهد شد كه گاز بيشتري به موتور ارسال ش ود و ماشين شتاب بگيرد.
16. الگوهاي طراحي
۱۶
نگرشي نو به شي گرايي
داستان از اين قراره كه روزي يك نفر از دهي به شهر مياد و از قضاي روزگار به يك كنسرت موسيقي ميره . در بازگشت از شهر
در راه به مطرب ده ميرسه كه داشته با پسرش ساز و دهل ميزده . همين كه مطرب رو مي بينه بهش ميگه كه من توي شهر رفتم يك
جايي به اسم كنسرت و كلي از همكارات رو يك جا ديدم . مطرب هم كه تا به اون روز كنسرت نديده و نشنيده بوده، با بهت مي
پرسه كه كنسرت چيه؟
مرد دهاتي ميگه كه كنسرت يه جايي كه اولش كه رفتيم تو يه عده روي يه بلندي با سازهاشون نشسته بود ند و هر كي براي
خودش هي ساز ميزد (حواستون كه هست داشتند سازهاشون رو كوك مي كردن د). بعد يكي كه اصلا ساز نداشت از در اومد تو و
همه براش دست زدند . بعد هم روشو كرد به مطربهاي روي بلندي و شروع كرد به دستور دادن كه تو بزن و تو نزن، تو بزن، تو نزن
و الي آخر . آخرش م به همشون گفت ديگه نزنيد . بعد هم مردم براش دوباره دست زدند و اون هي دولا و راست ميشد مي گفت من
.» نبودم اينا بودن من نبودم اينا بودن
ميان (collaboration) اين دقيقا تعريف يك سيستم شي گراست . دقيقا هدف يك سيستم شي گرا ايجاد هارموني معنادار
اجزاء مستقل سيستم ب راي دست يابي به يك كاركرد مشخص است . در صورتي كه در سيستمهاي ساخت يافته رويكرد ما دقيقا
رويكرد حل مساله بود . مساله تعريف مي شد و برنامه نويس مساله را هدف گرفته و براي حل آن با استفاده از يك سري دستورات
خطي شروع به حل مساله م يكرد . در منطق شي گرا اجزا يك سيست م الزاما تعلقي به سيستم ندارند و مي توانند به همان صورت كه
به ساير سيستم ها سرويس مي دهند به سيستم مورد نظر ما نيز سرويسي را ارايه كنند . تنها مساله توان طراح سيستم در ايجاد
تشريك مساعي و يا به تعبيري همكاري مناسب ميان اجزاء مختلف سيستم است
توجه : اين نوشته متعلق به خود من نمي باشد . و من اين نوشته را از وبلاگ در گذار عمر با ذكر منبع پست كرده بودم . به خاطر
نحوه نگرش جالب اين نوشته باز اين نوشته را اينجا قرار دادم و باز منبع را ذكر كردم تا رسم امانتداري را به جا آورده باشم.
17. الگوهاي طراحي
۱۷
مقدمه اي بر الگو هاي طراحي
كسي وجود دارد كه قبلاً مسله شما را حل كرده است .
در مهندسي نرم افزار يك الگوي طراحي، يك روش حل قابل تكرار براي مسائلي هست كه عموماً در طراحي نرم افزار با آن
برخورد مي كنيم . يك الگوي طراحي يك قالب يا شرح براي چگونگي حل مسائلي است كه مي تواند در شرايط مختلف استفاده
شود . يك الگوي طراحي، راه حلي است كه براي مستند سازي ارزشمند تشخيص داده شده است، بطوريكه توسعه دهند گان ديگر
مي توانند آن را در حل مسائل مشابه به كار ببرند .همانگونه كه طراحي شي گرا ادعا مي كند كه استفاد ه مجدد از كتابخانه ها و
قطعات را افزايش مي دهد، ادعا مي شود كه استفاده از الگو هاي طراحي، استفده مجدد از كتابخانه ها و قطعات را افزايش مي
دهد .
الگو ها تكنيك هايي هستند كه افراد زماني از آنها براي حل مسائل خاص استفاده كردند . و به عنوان راه حل هاي خوب شناخ ته
شده اند . سپس اين تكنيك ها مستند سازي شده اند تا توسعه دهندگان هنگام برخورد با مسائل مشابه از اين مستندات استفاده كنند
و مسائل خود را حل كنند .
تاريخچه الگو هاي طراحي :
استفاده از الگوها براي اولين بار به ذهن يك معمار به نام الكساندر خطور كرد . الكساندر با اين مشكل روبرو شد كه يك طرح
خوب و با كيفيت براي يك ساختمان چگونه مي تواند باشد . او براي حل مشكل خود، ساختمانها، خيابانها، شهرك ها و هر مكاني
كه يك انسان براي خودش مي سازد را مورد مطالعه و بررسي قرار داد . او كشف كرد كه بناهاي خوب از نظر طراحي داراي
ويژگيه اي مشترك هستند . او كشف كرد كه بناهاي خوب داراي ويژگيهاي مشابه هستند واين ويژگيهاي مشابه را الگو ناميد .
هر الگو بيانگر يك مسئله و مشكل است كه مي تواند بارها و بارها روي بدهد همراه با راه حل آن مسئله، وشما مي تواند از اين راه
حل براي ميليون ها بار استفاده ك ند بدون نياز مجدد براي پيدا كردن راه ح ل.
۱، بعضي از توسعه دهندگان نرم افزار با كارهاي الگساندر برخورد كردند . آنها با اين سوال روبرو شدند كه اگر در اوايل دهه ۹۹۰
الگو هاي طراحي معماري در اين رشته به صورت صحيح جواب مي دهد آيا مي توان الگوهاي را براي طراحي نرم افزار بوجود
آورد .
در نرم افزار چه مسائل وجو دارد كه بارها رخ مي دهد و تقريبا با روشهاي مشابه مي توان آنها را حل كرد؟ ·
18. الگوهاي طراحي
۱۸
آيا امكان استفاده از مفهوم الگوها در طراحي نرم افزار وجود دارد، آيا مي توان راه حل هاي را برا اساس الگوها بعد از ·
شناسايي الگوها ايجاد كر د.
س والات بالا، سوالاتي بودند كه توسعه دهندگان مطرح كردند و پاسخ آن را يافتند . پاسخ سوال بلي بود . مرحله بعدي شناسايي
الگوها بود و توسعه استانداردهاي براي مستند سازي الگوها .
در اوايل دهه ۱۹۹۰ ، افرادي زيادي روي الگوهاي طراجي كار مي كردند . اما چهار نفر به نام هاي ، گاما، جاكوبسون، هلم و
ولسايدز بيشترين تاثير را در اين زمينه با نوشتن كتابي به نام
داشتند . اين چهار نويسنده ، "Design Pattern: Elements of Reusable ObjectOriented
Software"
مشهور است . آنها در اين كتاب ائده استفاده از الگوها را در طراحي نرم افزار به كار بردند .و يك فرمت Gang of Four به
استاندارد را براي مستندسازي الگوها ايجاد كردند . ۲۳ نوع از الگوها را دسته بندي كردند و .... به مرور زمان فرمت هاي استاندارد
ديگري براي مستند سازي الگوها پيشهناد شد.
19. الگوهاي طراحي
۱۹
قالب مستند سازي براي الگوهاي طراحي :
نام الگو يك نام خوب و مفيد براي الگو
يك جمله كوتاه و مختصر درباره چيزي كه الگو انجام مي دهد . (i ntent ) هدف
(تعريف مسله و راه حل به صورت مختصر و مفيد )
نام مستعار نام هاي ديگري كه الگو با آن شناخته مي شود .
ساختار يك نمايش گرافيكي از الگو
اجزاء تشكيل دهنده
(P articipants )
كلاس ها و اشيائ كه در الگو شركت دارند ( وجود دارن د).
چگونه اجزاي تشكيل دهنده با هم همكاري مي كنند تا وظايفشان را (C ollaborations ) همكاريها
انجام دهند .
نتايج استفاده از الگوي مورد نظر (C onsequences ) نتايج
پياده سازي تكنيك هاي براي پياده سازي الگوي مورد نظر
نمونه كد تكه كدي براي پياده سازي يك نمونه
الگو هاي مرتبط الگوهاي طراحي ديگري كه ارتباط نزديگ با الگوي مورد نظر
دارند.
20. الگوهاي طراحي
۲۰
دسته بندي الگو ها :
همه الگو هاي كه در اين دسته قرار مي كيرند در ارتباط با روش :(C reational Pattern ) ۱ - الگوهاي بوجود آورنده
هاي ايجاد اشياء هستند .
اين نوع الگوها شرح مي دهند چگونه اشياء و كلاس ها مي توانند در :(S tructural Patten ) ۲ - الگوهاي ساختار ي
ساختارهاي بزرگتر باهم تركيب شوند .
اين نوع الگو ها روي ارتباط اش ياء با يكديگر تمركز دارن د. :(B ehavioral Pattern ) ۳ - الگوهاي رفتار ي
Creational Structural Behavioral
Factory Method
Abstract Factory
Builder
Prototype
Singleton
Adapter
Bridge
Composite
Decorator
Flyweight
Façade
Proxy
Interpreter
Template Method
Chain of Responsibility
Command
Iterator
Mediator
Memento
Observer
State
Strategy
Visitor
فهرست الگوهاي طراحي
21. الگوهاي طراحي
۲۱
Singleton Pattern
اشياء زيادي وجود دارند كه ما فقط و فقط به يك نمونه آن از اشياء نياز داريم . براي مثال سيستم شما فقط مي تواند فقط يك
را داشته باشيد يا در اداره شما فقط مي تواند يك مدير عامل وجود داشته باشد و .... حال فرض كنيد كه COM نمونه از پورت 1
شما كلاسي داريد كه فقط بايد يك نمونه از آن ايجاد شود . شما اين مسئله را چگونه حل مي كنيد؟
الگوي است كه براي اينكار ايجاد شده است . يعني اطمينان از اينكه از كلاس ما فقط يك نمونه ايجاد ، Singleton Pattern
شده است . اين الگو براي اين به كار مي رود تا ايجاد نمونه از يك كلاس را محدود كند .
نحوه پيادسازي :
آسانترين راه براي ايجاد كلاسي كه فقط مي تواند يك نمونه از آن ايجاد شود استفاده از يك متغيير استاتيك در داخل كلاس مي
مي دهيم و در ساير دفعات اين متغيير True باشد . اولين نمونه اي كه از اين كلاس ايجاد مي شود ما متغيير استاتيك را مقدار
باشد يك نمونه از شي ايجاد خواهد شد در غير اين صورت نمونه False استاتيك در سازنده تست مي شود اگر مقدارش
جديدي از آن شي ايجاد نخواهد شد.
VB.NET نمونه كد اول در
تعريف كلاس
Public Class Singleton
Private Shared instance_flag As Boolean = False
Private _Id As Integer
Public Property Id() As Integer
Get
Return _Id
End Get
Set(ByVal value As Integer)
_Id = value
End Set
End Property
Public Shared Function GetInstance() As Singleton
If (Not instance_flag) Then
instance_flag = True
Return New Singleton
Else
Return Nothing
End If
End Function
End Class
نحوه استفاده
22. الگوهاي طراحي
۲۲
Dim Ins1, Ins2 As Singleton
Ins1 = Singleton.GetInstance
Ins2 = Singleton.GetInstance
Ins1.Id = 200
Console.WriteLine(Ins1.Id)
Console.WriteLine(Ins2.Id)
Ins2.Id = 123
Console.WriteLine(Ins1.Id)
Console.WriteLine(Ins2.Id)
Console.ReadKey()
خروج ي: هنگام استفاده از كلاس بالا به شيوه اي كه نوشته شد نمونه دوم از آن هيچ وقت ايجاد نخواهد شد پس تمام
عملياتي كه نمونه دوم مي خواهد انجام دهد با خطا همراه خواهد بود . براي حل اين مشكل مي توانيم به صورت زير عمل
كنيم .
VB.NET نمونه کد دوم در
تعريف كلاس
Public Class Singleton
Shared m_instance As Singleton
Private _Id As String
Public Property Id() As Integer
Get
Return _Id
End Get
Set(ByVal value As Integer)
_Id = value
End Set
End Property
Public Shared Function GetInstance() As Singleton
If (m_instance Is Nothing) Then
m_instance = New Singleton()
End If
Return (m_instance)
End Function
Private Sub New()
End Sub
End Class
نحوه استفاده
Dim Ins1, Ins2 As Singleton
Ins1 = Singleton.GetInstance
Ins2 = Singleton.GetInstance
Ins1.Id = 200
Console.WriteLine(Ins1.Id)
Console.WriteLine(Ins2.Id)
Ins2.Id = 123
Console.WriteLine(Ins1.Id)
Console.WriteLine(Ins2.Id)
Console.ReadKey()
خروجي:
24. الگوهاي طراحي
۲۴
Factory Patterns
كارخان ه) ، دقيقا از معني لغوي آن مشخص است . كارخانه مكاني است كه در آن كالاها و محصولاتي توليد مي ) Factory مفهوم
كلاسي است كه نمونه هاي از كلاس هاي ديگر را با توجه به پارامترهاي كه Factory شود . و در بحث الگوهاي طراحي، يك
براي آن ارسال مي شود، ايجاد مي كند .
براي ايجاد يك ذهنيت در خودتان مي توانيد تصور كنيد كه ما يك فروشگاه پوشاك داريم هر وقت كه فروشگاه به لباس خاصي
ارسال مي كند و توليد كننده با توجه به اسامي ارسال شده آن لباس ها را (F actory ) نياز داشته باشيد . اسامي آن را به توليد كننده
ما است كه با توجه به پارامترهاي Factory توليد كرده و به فروشگاه ارسال مي كند . در اين مثال توليد كننده همان كلاس
ارسال شده ( ليست پوشاك مورد نظر فروشگا ه) لباس مورد نظر ( شي موزد نظ ر) را توليد مي كند و به مشتري ارسال مي كند.
VB.NET نمونه كد اول در
'Class Shirt
Public Class Shirt
Protected _Color As String
Protected _Size As String
Public ReadOnly Property Color()
Get
Return _Color
End Get
End Property
Public ReadOnly Property Size()
Get
Return _Size
End Get
End Property
End Class
'Class Shrit_A
Public Class Shrit_A
Inherits Shirt
Public Sub New()
Me._Color = "Blue"
Me._Size = "XL"
End Sub
End Class
'Class Shrit_B
Public Class Shirt_B
Inherits Shirt
Public Sub New()
Me._Color = "Red"
Me._Size = "M"
25. الگوهاي طراحي
۲۵
End Sub
End Class
'Class Factory
Public Class Factory
Public Function GetShirt(ByVal Type As String) As Shirt
If Type = "A" Then
Return New Shrit_A()
Else
Return New Shirt_B()
End If
End Function
End Class
'Class Store
Public Class Store
Private _OrderType As String
Public Property OrderType()
Get
Return _OrderType
End Get
Set(ByVal value)
_OrderType = value
End Set
End Property
Public Function Order() As Shirt
Dim Ins1 As New Factory
Dim Ins2 As Shirt = Ins1.GetShirt(_OrderType)
Return Ins2
End Function
End Class
نحوه استفاده
Private Sub Cmd_Order_Click(ByVal sender As System.Object, ByVal eAs System
.EventArgs)
Dim Ins1 As New Store
Dim INs2 As New Shirt
Ins1.OrderType = "A"
INs2 = Ins1.Order()
End Sub
26. الگوهاي طراحي
۲۶
دريچ ه) : ) Façade الگوي
الگوي دريچه در سيستم هاي استفاده مي شود كه توسعه دهندگان مي خواهند پيچيدگي يك سيستم را در يك كلاس (در بعضي
مواقع چند كلا س) مخفي كنند و با استفاده از اين كلاس و يا كلاس ها به عنوان واسط و ميانجي، پيچيدگي سيستم را كاهش
دهند .
اگر زير سيستمي حاوي چند كلاس باشد و اين كلاس ها با همديگر همكاري كنند تا سرويس هاي را كه قرار است زير سيستم
ارائه دهد را تداراك ببينند، ريسكي در ايجاد واسط به آن زير سيستم وجود دارد . هر كلاس ممكن است چندين عمليات داشته
باشد . زير سيستم هاي ديگر بايد توانايي ارسال پيام به نمونه هايي از هر كلاس را داشته باشند . به اين ترتيب، يك اتصال قوي بين
زير سيستم ها به وجود مي آيد و اگر تغيير در كلاس هاي يك زير سيستم ارائه دهنده سرويس بوجود بيايد، نيازمند رديابي تمامي
مكان ها در زير سيستم هاي هستيم كه عمليات اين كلاس ها را فراخواني كرده اند .
مي باشد، كه واسطي را به زير سيستم ايجاد مي كند و اين كلاس به façade يك روش غلبه بر اين وضعيت، ايجاد كلاس
عنوان نماينده زيرسيستم مورد نظر با زير سيستم هاي ديگر عمل مي كند . به اين ترتيب، تغيير در پياده سازي كلاس هاي زير
سيستم اثر محدودي بر زير سيستم ها ي ديگر دارد . و اگر تغييري در كلاس ها صورت بگيرد، فقط لازم است نقاطي در زير سيستم
ارسال شده اس ت. façade هاي ديگر پيدا شود كه در آنها، پيامي به نمونه هاي از كلاس
حالا با بررسي چند مثال مي توانيم تصويري بهتري از اين الگو به دست بياوريم .
تصور كنيد شما به عنوان مدير پروژه براي يك پروژه نسبتا بزرگ انتخاب شده ايد . در حالت اول شما خودتان وظيفه داريد
مسئوليت تك و تك افراد پروژه را به آنها بگويد و وظايف واگذر شده به آنها را تحويل بگيريد . در اين حالت شما وظيفه داريد با
تك و تك افراد ارتباط برقرار كنيد و همچنين براي با زخواست وظايف شما بايد نحوه ارتباط اين افراد را با يكديگر بدانيد . در
حالت دوم يك نفر به عنوان سر گروه انتخاب مي شود و شما مسئوليت ها واگذر شده را به او اعلام مي كنيد و براي تحويل
وظايف فقط از او بازخواست مي كنيد . حالا دو حالت را باهم مقايسه كنيد در كدام حا لت پيچيدگي و حجم كاري شما كم
استفاده كرديم . سر گروه در اين حالت به عنوان façade است؟ البته كه حالت دوم . در حالت دوم در واقع ما از الگوي
است. façade كلاس
27. الگوهاي طراحي
۲۷
نحوه ارتباط مدير پروژه با اعضاء – Façade شك ل ۱ : الگوي
براي مثال دوم در نظر بگيريد شما مسئول طراحي يك فروشگاه الكترونيكي هستيد كه در آن مشتري بايد قادر باشد براي پرداخت
مبلغ خريد خود از كارت هاي اعتباري استفاده كند . شما به يكي از شركت هاي صادر كننده كارت اعتباري مراجعه مي كنيد و
مي خواهيد نحوه استفاده و موارد مورد نياز براي اينكار را به شما ارائه دهد . شركت مورد نظر هيچ وقت ساختار و كلاس هاي
مورد نظر را كه در داخل برنامه خود براي اينكارها استفاده مي كنند دقيقا به شما ارائه نمي دهد . چون اين نه به نفع شركت مورد
نظر است نه به نفع شما، چون با اين كار پيچيدگي سيستم پرداخت دقيقا به برنامه شما نيز اضافه خواهد شد . پس چاره كار
را به عنوان ميانجي بين برنامه شما و برنامه سيستم façade شركت مورد نظر يك كلاس . façade چيست؟ استفاده از كلاس
پرداخت خودشان طراحي و در اختيار مشتريان خود قرار مي دهند و شما پيام هاي خود را به اين كلاس ارسال مي كند و آن نيز
براي گرفتن و ارسال پاسخ به شما، پيام مورد نظر را به كلاس اصلي ارسال مي كند و پاسخ را از آن دريافت و به شما ارسال مي
كند .
براي مثال آخر فرض كنيد شما وظيفه داريد يك برنامه براي ايجاد و ارسال ايميل بنويسيد كلاس هاي كه ممكن است براي اينكار
در نظر بگيريد مي تواند به صورت شكل زير باشد .
اين كلاس شامل بدنه پيام خواهد بود . : MessageBody كلاس ·
در صورت نياز شامل MessageBody اين كلاس نمونه سازي مي شود تا يك كلاس : Attachment كلاس ·
فايل پيوست باشد .
اين كلاس نمونه سازي مي شود تا شامل اطلاعات سرآيند فايل باشد : MessageHeader كلاس ·
.From,To,Subject,… مانند
28. الگوهاي طراحي
۲۸
را به MessageHeader و MessageBody اين كلاس نمونه سازي مي شود تا دو كلاس : Message كلاس ·
هم متصل كند ( پيوند بزن د).
اين كلاس نمونه سازي مي شود تا در صورت نياز پيام ارسالي رمز گذاري شو د. :S ecurity كلاس ·
اين كلاس نم ونه سازي مي شود تا در آخر پيام مورد نظر را به سرور مربوطه ارسال كند . : MessageSender كلاس ·
شكل زير نمودار كلاس هاي بالا را همراه با ارتباطات آنها نشان مي دهد .
نمودار كلاس ايجاد و ارسال ايميل ،F açade شك ل ۲ :الگوي
را مي تواند client با مشاهده تصوير بالا مي تواند حدس بزند كه كار با كلاس هاي كه براي اينكار در نظر گرفته ايد، كلاس
بيش از حد پيچيده كند . براي استفاده از اين كلاس ها، كلاس كلاينت بايد با اين ۶ كلاس و همچنين بايد با روابط بين آنها آشنا
استفاده كنيم يعني براي كاهش پيچيدگي از يك كلاس جديد façade باشد . دوباره براي كاهش پيچيدگي مي توانيم از الگوي
ا س تفاده مي كنيم . طرح جديد مي تواند به شكل زير باش د.
نمودار كلاس ايجاد و ارسال ايميل اصلاح شده ،Façade شک ل ۳: الگوي
29. الگوهاي طراحي
۲۹
نمودار كلاس الگوي دريچه :
نمودار كلاس الگو به صورت زير مي باش د.
Façade شك ل ۴ : نمودار كلاس الگوي
اجزاء تشكيل دهنده الگو :
كلاس ها و اشياء تشكيل دهنده اين الگو عبارتند از :
: façade كلاس ·
اين كلاس مي داند كه كلاس هاي زير سيستم بايد به پيام دريافت شده پاسخ دهند . o
پيام هاي دريافت شده را به شي مناسب براي پاسخگوئي ارسال مي كند . o
كلاس هاي زير سيستم : ·
آگاه نيستند . façade كلاس هاي زير سيستم از وجود كلاس o
پاسخ مي دهند . façade به پيام هاي ارسال شده توسط كلاس o
به كار برده بودم . ولي آقاي façade توجه : من در پست اصلي كه در وبلاگ موجود است، عنوان نما را به عنوان گزينه فارسي
مهندس مهرداد توصبه كردند كه به جاي نما از معادل دريچه استفاده كنيم كه به كاربرد آن نيز نزديگتر باشد .
Adapter Pattern
الگوي است كه در دنيا واقعي نمونه هاي زيادي از اين الگو ، (A dapter Pattern ، الگوي سازگارساز (وفق دهنده، مبدل
وجود دارد و به همين خاطر درك اين الگو زياد مشكل نخواهد بود.
30. الگوهاي طراحي
۳۰
شما داراي دو شاخه اي به شكل زير است ولي پريز هاي برقي laptop شكل زير را در نظر بگيريد و فرض كنيد كه كامپيوتر
كه در ديوار نصب شده است به شكلي است كه در سمت چپ تصوير نشان داده شده است . شما براي استفاده از لپ تاپ خود در
اين محل چه كاري را انجام مي دهيد؟
شما مي توانيد براي حل اين مشكل از يك مبدل استفاده كنيد . كه بين دو شاخه، لپ تاپ شما و پريز برق قرار مي گيرد و شما مي
توانيد با قرار دادن دو شاخه در مبدل و زدن مبدل به پريز از برق استفاده كنيد . در واقع مبدل، اينترفيس پريز را به گونه اي تغيير مي
دهد كه با اينترفيسي كه لپ تاپ شما نياز دارد همخواني داشته باشد .
مثال بالا يك مثال از دنيا واقعي بود . ولي يك وفق دهنده شي گرا چست؟ وفق دهنده هاي شي گرا دقيقا كار مشابهي را انجام مي
دهند . آنها يك اينترفيس را به گونه اي تغيير مي دهند كه سرويس گيرنده ها انتظار آنرا دارند .
وفق دهند هاي شي گرا :
فرض كنيد كه شما يك سيستم نرم افزاري داريد كه نياز دارد با كتابخانه ي از كلاس هاي جديد كه مربوط به فروشندگان است
كار كند، اما كلاس هاي جديد به گونه اي طراحي شده اند كه اينترفيس متفاوتي را نسبت به اينترفيس قبلي دارند .
براي حل اين مشكل شما چيكار مي كنيد؟ مي توانيد سيستم نرم افزاري موجود را به گونه اي باز نويسي كنيد كه با كلاس هاس
جديد همخواني داشته باشد . يا كلاس هاي جديد را به گونه اي تغيير مي دهيد كه با سيستم موجود همخواني داشته باشد . اما آيا
راه حل كم هزينه تري وجود ندارد كه بدون تغيير هيچ كدام از سيستم ها، سيستم كار خود را انجام دهد . شما مي توانيد يك
كلا س بنويسيد كه اينترفيس فروشندگان را به گونه اي تغيير بدهد كه سيستم موجود انتظار دارد.
31. الگوهاي طراحي
۳۱
سازگار ساز، وفق دهند ه) مانند يك واسطه عمل مي كند و درخواست هاي را كه از سيستم موجود مي رسد دريافت )A dapter
مي كند و آنها را به شكلي تغيير مي دهد و براي كلاس مورد نظر در سيستم فروشندگان ارسال مي كند كه قابل درك و اجرا براي
آن كلاس باشد .
تعريف شده است را نياز دارد . ولي Math را كه در اينترفيس 1 Max براي نمونه در شكل بالا كلاس كلاينت متدي به نام
كلاس هاي كه اين اينترفيس را پياده سازي مي كنند . عملي را كه كلاس كلاينت در نظر دارد انجام نمي دهند . ولي
پياده سازي شده است و دقيقا خواسته Imp است كه توسط كلاس 2 Maxvalue داراي عملي به نام Math اينترفيس 2
كلاس كلاينت را انجام مي دهد ولي با يك اينترفيس ديگر . براي حل اين مشكل چه پيشنهادي داريد؟
استفاده مي كنيم . يعني يك كلاس جديد تعريف مي كنيم كه اينترفيسي را ، (A dapter ) براي حل اين مشكل ما از يك مبدل
را طوري سر بار گذاري مي كنيم كه وقتي آن فراخواني مي Max كه كلاس كلاينت مي شناسد پياده سازي مي كند . ولي عمل
را فراخواني كند . Imp از كلاس 2 Maxvalue شود . عمل
: Adapter نمودار كلاس
نمودار كلاس الگو به صورت زير است:
33. الگوهاي طراحي
۳۳
State Pattern
حال شما چطور است؟، سوالي است كه در يك روز بارها از شما پرسيده مي شود يا شما از ديگران مي پرسيد . حال شما يك
ويژگي ثابت شما نيست بلكه يك ويژگي پويا است كه ممكن است با توجه به رويدادهاي خارجي يا دروني تغيير كن د. و شما مي
توانيد در مقابل يك رويداد مشابه با توجه به حالتان رفتار متفاوتي از خود نشان دهيد .
علاوه بر خودمان اكثر اشياي كه در اطراف ما قرار دارند داراي حالت هاي متفاوتي هستند و با توجه به رويداد هاي بيروني و
داخلي از حالت به حالت ديكر مي رو ند و رفتار متفاوتي را در هر حالت از خود بروز مي دهند .
در حال ديدن يك فيلم هستيد . اين برنامه دكمه هاي ،W indows Media Player براي مثال فرضي كنيد با يك برنامه مانند
دارد كه با كليك روي آنها مي توانيد برنامه را به حالت همنام با آن دكمه ببري د. پس براي اين Stop و Pause ،P lay مانند
شي، سه حالت بالا را مي توانيد در نظر بگيري د. حال تصوير كنيد كه يك برنامه شبيه به مثال بالا را خودمان مي خواهيم بنويسيم .
،M edia Player يكي از شيوه ها براي انجام اين كار مي تواند به اين ترتيب باشد كه ما در ابتدا تمام حالاتي را كه يك شي
مي تواند قبول كند را جمع آوري مي كنيم . در مرحله دوم براي هر حالت يك متغيير تعريف مي كنيم و مقادير مربوط به آنها را
مشخص مي كنيم و علاوه بر اينها يك متغيير براي نگهداري حالت فعلي شي در نظر مي گيري م.
const int play=0;
const int stop=1;
const int pause=2;
int state = stop; // حالت اوليه
سپس تمام اعمالي و رويدادهاي كه در سيستم مي تواند رخ دهد را جمع آور مي كنيم . و در انتها يك كلاس ايجاد مي كنيم كه
به عنوان يك ماشين حالت عمل كند، براي هر عمل يك متد ايجاد مي كنيم كه جملات شرطي را به كار مي برند تا رفتار مناسبي
را كه در هر حالت نياز است را پياده سازي كنند .
public void Stop()
{
if (state == play)
{
عمليات مورد نظر//
}
if (state == pause)
{
عمليات مورد نظر//
}
if (state == stop)
{
عمليات مورد نظر//
}
}
روش بالا مي تواند براي پياده سازي يك شي كه داراي چندين حالت است به كار برود . ولي تصور كند كه يك حالت جديد را
بخواهيم به شي اضافه كنيم و يا در نحوه عملكرد شي در يك حالت خاص تغيير دهيم مطمئنا كار مشكلي را خواهيم داشت .
يك روش خوب و كارا براي پياده سازي اشياي كه در طول حيات خود مي توانند چندين حالت مختلف داشته باشند، مي تواند
چگونه باشد؟ شايد شما پاسخ هاي خوب و بهتري بتوانيد ارائه كنيد . ولي يكي از روش ها مي تواند به صورت زير باشد:
34. الگوهاي طراحي
۳۴
تعريف مي كنيم كه شامل يك متد براي هر عملي است كه شي مورد نظر مي تواند state ۱. در ابتدا يك اينترفيس به نام
ا نجام دهد .
را پياده سازي مي كند . در واقع اين state ۲. در مرحله دوم براي هر حالت شي يك كلاس تعريف مي كنيم كه اينترفيس
كلاس مسول پاسخگويي به رويدادها است . زمانيكه شي در اين حالت قرار دارد .
تعريف مي كنيم . سپس براي هر state در ابتدا ما يك كلاس اينترفيس به نام ،M edia Player براي نمونه در همان مثال
را پياده سازي مي كند . براي پياده سازي هر حالت ما نياز داريم تا رفتار state حالت يك كلاس تعريف مي كنيم كه اينترفيس
هر كلاس را مشخص كنيم هنكاميكه هر عمل فرا خواني مي شود .
مي رسيم . اين ( M edia Player ) بعد از پياده سازي تمام حالات شي مورد نظر، به كلاس اصلي يا همان كلاس شي مورد نظر
كلاس همان متد هاي روش اول را خواهد داشت اما با چندين تفاوت :
۱. به جاي استفاده از متغييرهاي عددي براي هر حالت و حالت فعلي، از اشياء كه براي حالت ها تعريف كرديم استفاده مي
كنيم .
كد جديد كد قديمي
public class MediaPlayer{
State MediaState;
PlayState playstate;
PauseState pausestate;
StopState stopstate;
MediaPlayer{
playstate = new PlayState();
new PauseState (); = pausestate
stopstate = new StopState();
MediaState = stopstate;
}
Public class MediaPlayer{
const int play=0;
const int stop=1;
const int pause=2;
MediaPlayer{
const int state = stop; // حالت اوليه
}
35. الگوهاي طراحي
۳۵
۲. در پياده سازي عمل ها ديگر از جملات شرطي استفاده نمي كنيم . بلكه وقتي عملي فراخواني مي شود آن عمل به كلاس
حالت فعلي براي انجام واگذار مي شود .
public void Stop()
{
MediaState.stop();
}
حالت فعلي اجاره خواهد شد بدون هيچ جمله ي شرط ي. stop اشاره گر به حالت فعلي اس ت. متد MediaState چون
:( State Pattern) نمودار الگوي حالت
ما تا اينجا يك الگوي حالت را بطور كامل پياده سازي كرديم . ولي دوباره نكات بالا را باهم بررسي مي كنيم .
۱. رفتار يك شي توسط حالت داخلي آن شي مشخصي مي شود كه در مقابل رخ دادن يك رويداد مي تواند تغيير كند .
۲. تعداد حالات يك شي را بايد بتوانيم افزايش بدهيم بدون اينكه مجبور باشيم قسمت هاي زيادي از كد را مرور كنيم يا
تغيير دهيم .
الگوي حالت، به يكي شي اجازه مي دهد رفتارش را زمانيكه حالت داخلي شي تغيير كند، تغيير دهد . و همچنين با در نظر گرفتن
هر حالت به عنوان يك شي جداگانه، حالات شي را نهان سازي مي كند . و ما مي توانيم هر تعداد حالات مورد نظر را به شي
تغيير انجام دهيم . context مربوطه اضافه كنيم بدون اينكه در پياده سازي كلاس
.M edia Player كلاسي است كه مي تواند داراي چندين حالت داخلي باشد در مثال ما همان Context كلاس
يك اينترفيس مشترك براي همه حالت ها تعريف مي كند . State اينترفيس
PlayState, عمل هاي را كه شي در آن حالت انجام مي دهد، پياده سازي مي كنند .( كلاسهاي ، Concrete كلاس هاي
(StopState,PauseState
36. الگوهاي طراحي
۳۶
(Chain of Responsibility pattern) الگوي زنجيره مسئوليت
يك سرويس دهنده اينترنتي را در نظر بگيريد . اين شركت داراي سه سطح پشتيباني به شرح زير براي كاربران اس ت:
سطح ۱ : در اين سطح به مشكلات ابتدايي كاربران مانند فراموش كردن كلمه عبور كاربران و ... رسيدگي مي شود .
سطح ۲ : اگر اعضاي گروه سطح ۱ نتوانند مشكل مورد نظر را حل كنند . مشكل براي حل به گروه سطح ۲ ارجاع داده مي شود .
سطح ۳ : اگر اعضاي گروه ۲ نيز نتوانند مشكل مورد نظر را حل كنند . مشكل براي حل به گروه سطح ۳ ارجاع داده مي شود . در اين
سطح براي حل مشكل يك قرار ملاقات در محل مشكل با مشتري گذاشته مي شود .
همانطوريكه در مثال بالا مشخص است . ممكن است هر كدام از گروه ها به در خواست ارائه شده پاسخ دهند . ولي دقيقا مشخص
نيست كدام گروه به در خواست ارائه شده پاسخ خواهد داد . اما همه گروه ها بايد شانس اين را داشته باشند كه به درخواست ارائه
شده پاسخ دهند . اين شانس اولويت دار است . براي نمونه در مثال بالا ابتدا به تيم سطح ۱ اين شانس داده مي شود تا مشكل را حل
كند . در صور ت عدم حل مشكل به ترتيب، شانس به تيمهاي ۲ و ۳ داده مي شود . اين امكان نيز وجود دارد كه هيچ يك از تيم ها
نتوانند اين مشكل را حل كنند و درخواست ارائه شده بدون پاسخ بماند .
زنجيره مسئولي ت) مي باشد . ) Chain of responsibility مثالي كه در بالا ارائه شده تقريبا تعريفي از الگوي
در اين الگو به يك شي اجازه داده مي شود در خواستي را ارسال كند بدون اينكه بداند كدام شي يا اشياء آنرا دريافت خواهند
كرد و به آن پاسخ خواهند داد . اين كار با ارسال درخواست به زنجيره اي از اشياء صورت مي گير د. هر شي در اين زنجيره مي
تواند به درخواست ارائه شده پاسخ دهد يا آن را به شي بعدي در زنجيره ارسال كند . در واقع هر شي در زنجيره بعنوان يك
پاسخگو براي درخواست ارائه شده عمل مي كند . اگر شي مورد نظر بتواند درخواست راجواب دهد، پاسخ آن را مي دهددر غير
اينصورت آن را به شي جانشين اش ( شي بعدي در زن جير ه) ارسال مي كند .
براي ادامه موضوع يك مثال ديگر را در نظر مي گيريم . فرض كنيد شما مسول نوشتن يك برنامه براي شبيه سازي فرآيند تائيد
يك درخواست سفارش از يك شركت هستيد . در اين شركت، بعد از اينكه درخواستي توسط مشتري ارائه مي شود بايد در ابتدا
توسط مدير تائيد شود و در صورت تائيد توسط مدير، جنس به مشتري فروخته خواهد شد . اين شركت داراي چهار سطح
مديريت مي باشد و مشخص شده است كه هر مدير سفارشاتي با مبلغ چقدر را مي تواند تائيد كند . كه حد مبالغي كه مي توانند
تائيد كنند در جدول زير مشخص شده اس ت.
سطوح مديريت مبلغ سفارش
مدير نمايندگي ۲۵۰۰۰
مدير ناحيه ۱۰۰۰۰۰
نايب رئيس ۲۰۰۰۰۰
رئيس ۴۰۰۰۰۰
37. الگوهاي طراحي
۳۷
شما براي اينكار چه الگوي را پيشنهاد مي كنيد؟
اجاز ه بدهيد كار را با الگوي زنجيره مسولئيت ادامه دهيم . در ابتدا يك كلاس براي سفارش به نام سفارش خريد در نظر مي
گيري م.
سپس يك كلاس انتزاعي به نام مديريت سفارش تعريف مي كنيم كه داراي يك اينترفيس مشترك براي هر كدام از سطوح
مديريت اس ت. كه نمودار كلاس مربوط به مديريت سفارش و سطوح مديريت به صورت زير خواهد بود . كه متد تعيين شي
براي مشخص كردن شي بعدي ( شي جانشي ن) در زن جيره عمل مي كن د. ، (S etSuccessor ) جانشين
براي تائيد يك سفارش، كارهاي زير صورت خواهد گرفت :
۱. ايجاد يك مجموعه از اشياي كه مي توانند به درخواست هاي رسيده شده پاسخ بدهند ( سطوح مديري ت). و قرار دادن
آنها در يك زنجيره به طور مرتب بر حسب مقاديري كه مي توانند تائيد كنند . هر يك از اين اشياء توسط
(M ain به شي بعدي متصل مي شود . (كلاس SetSuccessor متد
۲. يك درخواست تائيد به اولين شي موجود در زنجيره ارسال مي شود كه اين كار توسط فراخواني
آن شي انجام مي شود . اگر مبلغ سفارش از مقدار مبلغي كه ان شي ني تواند تائيد كند كوچكتر authorize متد
باشد، آنرا تائيد مي كند در غير اينصورت آن درخواست را به شي بعدي در زنجيره ارسال مي كند . (براي مثال در كد
را بررسي كنيد . ) BranchManager زير مي توانيد كلاس
38. الگوهاي طراحي
۳۸
كلاس مديريت سفارش
abstract class RHandler
{
protected RHandler successor;
public void SetSuccessor(RHandler successor)
{
جانشين شی تعيين//
this.successor = successor;
}
public abstract void authorize (PurchaseRequest purchase);
}
كلاس مدير نمايندگي
class BranchManager: RHandler
{
public override void authorize (PurchaseRequest purchase)
{
تائيد سفارش//
if (purchase.Amount <=25000)
{
}
else if (successor != null)
{
successor.ProcessRequest(RegionalDirector);
}
}
}
Main كلاس
class MainApp
{
static void Main()
{
BranchManager A = new BranchManager();
RegionalDirector B = new RegionalDirector();
VicePresident C = new VicePresident();
President D = new President();
A.SetSuccessor(B);
B.SetSuccessor(C);
C.SetSuccessor(D);
Purchase p = new Purchase( 1, "Order 1",15000);
A.authorize(p);
Purchase p = new Purchase( 2, "Order 2",110000);
A.authorize(p);
}
}
40. الگوهاي طراحي
۴۰
Template method
بعضي ار مردم نمي توانند زندگي را بدون قهوه تصور كنند و بعضي ديگر زندگي را بدون چاي نمي توانند تصور كنند . ولي جزء
تشكيل دهنده اصلي هر دو كافئين است . شباهت هاي ديگر نيز بين اين دو مورد وجود دارد . روش ساخت هر دوي آنها تقريبا
مشابه است . شما اغلب موارد به ترتيب زير عمل مي كنيد .
دستوالعمل ساخت قهوه :
۱. مقداري آب را مي جوشانيد .
۲. مقدار قهوه در آب جوشانده شده مي ريزد تا دم بكشد .
۳. فهوه را در فنجان مي ريز د.
۴. مقداري شكر و يا شير به آن اضافه مي كنيد .
دستورالعمل ساخت چا ي:
۱. مقداري آب را مي جوشانيد .
۲. مقدار چاي خشك در آب جوشانده شده مي ريزد تا دم بكشد .
۳. چاي را در فنجان مي ريز د.
۴. مقداري شكر به آن اضافه مي كنيد .
اگر بخواهيم برنامه اي براي تهيه چاي و قهوه بنويسيم كلاس هاي را به صورت زير خواهيم داشت .
كلاس قهوه
Public Class Coffee
' هر مرحله از دستورالعمل ساخت قهوه به عنوان يک متد در نظر گرفتهشده اس ت.
Public Sub prepareRecipe()
' مراحل تهيه قهوه
boilWater()
brewCoffeeGrinds()
pourInCup()
addSugereAndMilk()
End Sub
Public Sub boilWater()
Console.WriteLine(" ("جوشاندن آب
End Sub
Public Sub brewCoffeeGrinds()
Console.WriteLine(" ("ريختن پودر قهوه به داخل آب جوشانده شده
End Sub
Public Sub pourInCup()
Console.WriteLine(" ("ريختن قهوه به فنجان
End Sub
Public Sub addSugereAndMilk()
Console.WriteLine(" ("اضافه کردن شير و شکر
End Sub
End Class
41. الگوهاي طراحي
۴۱
كلاس چاي
Public Class Tea
Public Sub prepareRecipe()
boilWater()
brewTea()
pourInCup()
addSugere()
End Sub
Public Sub boilWater()
Console.WriteLine(" ("آب جوشاندن
End Sub
Public Sub brewTea()
Console.WriteLine(" ("ريختن چای به داخل آب جوشانده شده
End Sub
Public Sub pourInCup()
Console.WriteLine(" ("ريختن چای به فنجان
End Sub
Public Sub addSugere()
Console.WriteLine(" ("اضافه کردن شکر
End Sub
End Class
دقيقا مشابه يكديگر هستند . پس pourInCup و boilWater با مشاهده دو كلاس بالا مشاهده مي شود كه دو متد
طراحي ما داراي اشتباه هست چون بعضي از كدها تكرار شده اند . پس ما بايد طراحي خود را تغيير دهيم . ما مي توانيم طراحي
خود را به صورت زير تغيير دهيم . دو متد كاملا مشابه در كلاس پايه پياده سازي مي شود . اما چون
در هر كلاس به صورت نتفاوت عمل مي كند . اين متد در زير كلاس هاي مربوطه پياده سازي مي prepareRecipe متد
شود .
طراحي بالا يك طراحي خوب است اما نمي شود طراحي را بهتر از اين كرد؟ اگر توجه كنيم متوجه مي شويم كه براي تهيه هر
دو مورد الگوريتم يكساني را به كار مي بري م:
۱. جوشاندن آبي
۲. اضافه كردن چاي يا قهوه به آب جوشيده شده
۳. ريختن نوشيدني به دست امده در فنجان
42. الگوهاي طراحي
۴۲
۴. اضافه كردن چاشني مورد نظر به نوشيدني
را در كلاس پايه پياده سازي كني م. prepareRecipe پس ما مي توانيم با كمي تغييرات متد
Public Sub prepareRecipe()
boilWater()
brewTea()
pourInCup()
addSugere()
End Sub
Public Sub prepareRecipe()
boilWater()
brewCoffeeGrinds()
pourInCup()
addSugereAndMilk()
End Sub
همانطوريكه مي توانيد مشاهده كنيد كلاس مر بوط به قهوه متدهاي به
را استفاده مي كند در حاليكه كلاس مربوط به چاي از addSugereAndMilk و brewCoffeeGrinds نام
استفاده مي كند . يك راه حل اين است كه براي هر مرحله غير مشابه يك نام addSugere و brewTea متد هاي به نام
تغيير دهيم . و نام brew را به brewCoffeeGrinds و brewTea مشترك در نظر بگيريم . نام متدهاي
تغيير مي دهيم . پس addCondiments را به addSugere و addSugereAndMilk متدهاي
براي هر دو كلاس به صورت زير تغيير مي كند . prepareRecipe متد
Public Sub prepareRecipe()
boilWater()
brew ()
pourInCup()
addCondiments()
End Sub
پس حالا مي توانيم اين متد را بطور كامل به كلاس پايه منتقل كنيم و طراحي را به صورت زير تغيير دهيم .
Template حالا ما براي اين مسله به يك طراحي ائده ال دست يافتيم . كاري كه ما براي حل اين مسله انجام داديم به نام الگوي
از كلاس پايه درك prepareRecipe شناخته مي شود . دليل نامگذاري اين الگو را مي توانيم با مشاهده متد method
43. الگوهاي طراحي
۴۳
يك متد است و دوما به عنوان يك قالب براي الگوريتم به كار مي رود . براي نمونه در prepareRecipe كنيم . اولين اينكه
اين مثال شامل الگوريتم تهيه يك نوشيدني مي باشد .
مراحل انجام يك الگوريتم را در يك متد در كلاس پايه تعريف مي كند و اجازه مي دهد زير ، Template method الگوي
كلاس ها يك يا چند مرحله از الگوريتم را پياده سازي كنند . در واقع اسكلت يك الگوريتم در يك متد تعريف مي شو د.
هدف ما در اين الگو، ايجاد يك قالب براي يك الگوريتم است . يك قالب يك الگوريتم را به صورت مجموعه اي از مراحل
تعريف مي كند . هر كد ام از اين مراحل به عنوان يك متد در نظر گرفته مي شود . كه بعضي از متدها در همان كلاس پايه پياده
در كلاس پايه در نظر گرفته مي شود و در زير كلاس ها پياده سازي مي abstract سازي مي شود و بعضي از متدها به صورت
شود .
: UML نمودار
است . كه الگوي Abstract يك كلاس AbstractClass اين الگو به صورت بالا است . كه در آن كلاس UML نمودار
است ( يك مرحله از الگوريت م) كه در Abstract يك متد primitiveOperation قالب در آن تعريف مي شود . و متد
زير كلاس پياده سازي خواهد شد . همانطوريكه در مثال بالا مشاهده كرديم مي تواند بيش از يك
وجود داشته باشد . اين حالت زماني رخ مي دهد كه بعضي از مراحل الگوريتم بتواند در روش هاي ConcerteClass كلاس
مختلف پياده سازي شود.
44. الگوهاي طراحي
۴۴
(Strategy Pattern) الگوي استراتژي
در زندگي روزمره خود به مسائلي برخورد مي كنيم و براي غلبه بر اين مسائل ممكن است چندين راه حل پيش رو داشته باشيم . ما
با توجه به شرايط خود يا به اجبار يكي از اين راه حل ها را انتخاب مي كنيم . در طراحي و پياده سازي يك نرم افزار نيز اين شرايط
وجود دارد يعني جهت انجام يك عمل خاص مي توانيم از چندين الگوريتم خاص استفاده كنيم در اين حالت مي توانيم برنامه را
طو ري طراحي كنيم كه خود برنامه به صورت پويا الگوريتم با بازدهي بالاتر را اتنخاب كند يا اين امكان را به برنامه كلاينت
يا كاربر بدهيم تا يكي از الگوريتم ها را جهت انجام آن عمل انتخاب كند .
براي مثال فرض كنيد كه ما در حال طراحي يك برنامه مسيريابي براي يك شبكه ه ستيم . همانطوريكه مي دانيم براي مسير يابي
الگوريتم هاي مختلفي وجود دارد كه هر كدام داراي مزايا و معايبي هستند . و با توجه به وضعيت موجود شبكه يا عملي كه قرار
است انجام پذيرد بايد الگوريتمي را كه داراي بالاترين كارائي است انتخاب كنيم . همچنين اين برنامه بايد ام كاني را به كاربر بدهد
كه كارائي الگوريتم هاي مختلف را در يك شبكه فرضي بررسي كنيد . حالا طراحي پيشنهادي شما براي اين مسله چست؟
دوباره فرض كنيد كه در مثال بالا در بعضي از الگوريتم ها نياز داريم كه گره هاي شبكه را بر اساس فاصله ي آنها از گره مبداء
مرتب كنيم . د وباره براي مرتب سازي الگوريتم هاي مختلف وجود دارد و هر كدام در شرايط خاص، كارائي بهتري نسبت به
الگوريتم هاي ديگر دارد . مسئله دقيقا شبيه مسئله بالا است و اين مسله مي توانند داراي طراحي شبيه مسله بالا باش د. پس اگر ما
بتوانيم يك طراحي خوب براي اين مسئله ارائه دهيم مي توانيم اين طراحي را براي مسائل مشابه به كار ببريم .
هر كدام از ما مي توانيم نسبت به درك خود از مسئله و سليقه كاري، طراح هاي مختلفي براي اين مسئله ارائه دهيم . اما يك
طراحي كه مي تواند يك جواب خوب و عالي باشد، الگوي استراتژي است كه توانسته است بارها و بارها به اين مسئله پاسخ بدهد .
الگوي استراتژي گزينه مناسبي براي مسائلي است كه مي توانند از چندين الگوريتم مختلف به مقصود خود برسند .
اين الگو بصورت زير اس ت: UML نمودار
اجازه بدهيد، شيوه كار اين الگو را با مثال مربوط به مرتب سازي بررسي كنيم . فرض كنيد كه ما تصميم گرفتيم كه از سه الگويتم
زير براي مرتب سازي استفاده كنيم.
45. الگوهاي طراحي
۴۵
Shell Sort ۱
Quick Sort ۲
Merge Sort ۳
ما براي مرتب سازي در اين برنامه داراي سه استراتژي هستيم . كه هر كدام را به عنوان يك كلاس جداگانه در نظر مي گيريم
بتواند به سادگي يك از استراتژي ها را انتخاب كنيد Client براي اينكه كلاس .(C oncreteStrategy (همان كلاس هاي
تعريف abstract بهتر است كه تمام كلاس هاي استراتزي داراي اينترفيس مشترك باشند . براي اين كار مي توانيم يك كلاس
كنيم و ويژگيهاي مشترك كلاس هاي استراتژي را در آن قرار دهيم و كلاس هاي استر اتژي آنها را به ارث ببرند (همان
و پياده سازي كنند . (S trategy كلاس
كه كلاس هاي استراتژي آنرا به ارث مي برن د. abstract كلاس
abstract class SortStrategy
{
public abstract void Sort(ArrayList list);
}
QuickSort کلاس مربوط به
class QuickSort : SortStrategy
{
public override void Sort(ArrayList list)
{
الگوريتم مربوطه //
}
}
ShellSort کلاس مربوط به
class ShellSort : SortStrategy
{
public override void Sort(ArrayList list)
{
الگوريتم مربوطه //
}
}
MergeSort کلاس مربوط به
class MergeSort : SortStrategy
{
public override void Sort(ArrayList list)
{
الگوريتم مربوطه //
}
}
كه يكي از استراتزيها را براي مرتب كردن ليست به كار مي بر د. Context كلاس
class SortedList
{
private ArrayList list = new ArrayList();
private SortStrategy sortstrategy;
public void SetSortStrategy(SortStrategy sortstrategy)
{
this.sortstrategy = sortstrategy;
46. الگوهاي طراحي
۴۶
}
public void Add(string name)
{
list.Add(name);
}
public void Sort()
{
sortstrategy.Sort(list);
}
}
47. الگوهاي طراحي
۴۷
Observer Pattern
شايد شما هم زمانيكه تلويزيون را باز مي كنيد، يا وارد اينترنت مي شود، يكراست به سراغ شبكه ها يا سايت هاي خبري مي رود،
تا از اتفاقات و رويدادهاي مورد علاقه خود آگاه شود . حتي بعضي وقت ها اين خبرها و رويدادها باعث مي شوند شما روند كاري
خود را تغيير ده يد . حتي بعضي از خبرها در موضوعات خاص براي شما آنقدر اهميت دارد كه، عضو يك سايت خبري مي شود تا
هر زمانيكه خبر جديدي وجود داشته باشد، به ايميل شما نيز ارسال شود . بنابراين هر زمانيكه يك خبر جديد به سايت اضافه مي
شود، آن خبر به ايميل شما نيز ارسال مي شود . تا زمانيكه شما از عضويت در آن سايت انصراف نداديد، همه خبرهاي جديد به شما
ارسال مي شود، و زمانيكه شما از عضويت خود انصراف داديد، خبرهاي جديد به شما ارسال نخواهد شد ولي براي اعضاء ديگر
سايت ارسال خواهد شد . اگر شما مسئول طراحي اين سيستم بوديد، چگونه عمل مي كرديد؟
يك مركز كاريابي را در نظر بگيريد، افراد مختلفي با تخصص هاي مختلف، به اين مركز مراجعه مي كنند، و با توجه به تخصص
هايشان براي درخواست كار ثبت نام مي كنند . هر زمانيكه درخواست نيرو توسط يك شركت در يك تخصص خاص از آن
مركز شد . آن مركز افرادي را كه در آن تخصص ث بت نام كرده اند، از آن موقعيت كاري مطلع مي كنند . اگر قرار باشد شما يك
سيستم نرم افزاري براي اين كار طراحي كنيد، طراحي شما به چه صورت خواهد بود؟
هر كدام از ما مي توانيم نسبت به درك خود از مسئله و سليقه كاري، طراح هاي مختلفي براي اين مسئله ارائه دهيم . اما يك
است كه توانسته است بارها و بارها به اين مسئله پاسخ Observer طراحي كه مي تواند يك جواب خوب و عالي باشد، الگوي
بدهد .
در هر دو مسئله بالا، ما يك شي داريم كه مجموعه اي از اشياء به آن وابسته هستند . هر زماني كه وضعيت شي مورد نظر تغيير مي
هاي مي ناميم و شي را كه ديگر Observer كند، اشياء ديگر از آن تغيير آگاه مي شوند . در اين الگو، مجموعه اشياء وابسته را
مي ناميم . براي نمونه در مثال اول، افرادي كه در سايت عضو مي شوند يك Subject اشياء به آن وابسته هستند را
هست . Subject هستند . و شي خبر، همان Observer شي
يك وابستگي، يك به چند بين اشياء هست، هنگاميكه شي طرف يك، وضعيتش تغيير كند، اشياء وابسته Observer الگوي
مطلع مي شوند و وضعيت خودشان را با توجه به آن وضعيت بروز رساني مي كنند .
مكانيزم عملكرد اين الگو بصورت زير اس ت:
و اطلاع از (u nregistering ) و انصراف از عضويت (r egistering ) بايد يك اينترفيس براي ثبت Subject - ۱
تغييرات را آماده كند .
ها ارسال observer ها براي آن ريجستر شده اند را به observer ، بايد اطلاعات حالتي را كه Subject - ۲
كند .
آماده كند . Subject بايد يك اينترفيس براي دريافت پيام از Observer - ۳
نمودار كلاس اين الگو بصورت زير است:
48. الگوهاي طراحي
۴۸
با يك مثال ديگر كار را ادامه مي دهيم . فرض كنيد كه در اداره شما ، در داده هاي پايگاه داده مركزي تغييرات غير مجازي، داده
شده است . براي حل اين مشكل مديران پيشنهاد كرده اند كه هر تغييري كه در پايگاه داده مي شود، بايد توسط يك پيام، به افراد
را در نظر مي گيريد . دقيقا بر طبق نمودار عمل مي Observer مشخص شده اي اعلام شود . شما براي حل اين مشكل، الگوي
كنيم و با يك حالت فرض اين مثال را پياده سازي مي كنيم .
subject اينترفيس مربوط به
Public Interface subject
Sub Attach(ByVal Ins As Observer)
Sub Detach(ByVal Ins As Observer)
Sub Notify()
End Interface
Observer اينترفيس مربوط به
Public Interface Observer
Sub Update(ByVal operation As String, ByVal record AsString)
End Interface
را پياده سازي مي كند . subject كه اينترفيس مربوط به database كلاس
Public Class dataBase
Implements subject
Private observers As ArrayList
Private operation As String
Private record As String
Public Sub New()
observers = New ArrayList
End Sub
Public Sub Attach(ByVal Ins As Observer) Implementssubject.Attach
observers.Add(Ins)
End Sub
Public Sub Detach(ByVal Ins As Observer) Implementssubject.Detach
observers.Remove(observers)
End Sub
Private Sub Notify() Implements subject.Notify
For I As Integer = 0 To observers.Count – 1
49. الگوهاي طراحي
۴۹
Dim Ins As Observer = observers(i)
Ins.Update(operation, record)
Next
End Sub
Public Sub editDatabase(ByVal ope As String, ByVal rec AsString)
Me.operation = ope
Me.record = rec
Notify()
End Sub
End Class
را پياده سازي مي كند . Observer كه اينترفيس Archiver كلاس
Public Class Archiver
Implements Observer
Public Sub Update(ByVal operation As String, ByVal recordAs String)
Implements Observer.Update
MessageBox.Show("The archiver says a " + operation + " operation
was performed on " + record)
End Sub
End Class
را پياده سازي مي كند . Observer كه اينترفيس boss كلاس
Public Class Boss
Implements Observer
Public Sub Update(ByVal operation As String, ByVal recordAs String)
Implements Observer.Update
MessageBox.Show("The boss says a " + operation + " operation was
performed on " + record)
End Sub
End Class
را پياده سازي مي كند . Observer كه اينترفيس client كلاس
Public Class client
Implements Observer
Public Sub Update(ByVal operation As String, ByVal recordAs String)
Implements Observer.Update
MessageBox.Show("The client says a " + operation + " operation
was performed on " + record)
End Sub
End Class
تست
Dim DB As New dataBase
Dim Ar As New Archiver
Dim Bo As New Boss
Dim Cl As New client
DB.Attach(Ar)
DB.Attach(Bo)
DB.Attach(Cl)
DB.editDatabase("Delete", "Record 1")
داريم . كه هر وقت تغييري در پايگاه داده اعمال مي شود، با يك پيام به آنها اعلام مي Observer در مثال بالا، ما سه نوع
شود.
50. الگوهاي طراحي
۵۰
Memento الگوي
نمي دانم تا بحال پشت كاميوتر خودتان نشستيد تا يك مرحله از يك بازي كامپيوتري را به پايان برساند يا نه؟ اما كساني كه اينكار
را انجام دادند تصور كنند يك بازي استراتژيك مانند كمانندو ها را بازي مي كنند اما بازي بدون قابليت ذخيره كردن ارائه شده
است . در اين حالت حتما اكثر افراد اين بازي را خيلي زود كنار خواهند گذاشت چون واقعا كار كاربر خيلي سخت خواهد شد .
پس اگر روزي قرار باشد يك بازي كامپيوتري را طراحي و پياده سازي كنيم براي برآورده كردن نياز هاي كاربر حتما بايد بازي
را با قابليت ذخيره كردن طراحي و پياده سازي كنيم .
اجازه بدهيد يكبار ديگر مسئله را تعريف كنيم : فرضي كنيد شما در حال طراحي يك بازي هستيد . اين بازي بايد با قابليتي ارائه
شود كه كاربر در هر قسمتي از بازي خواست بتوانيد بازي را در آن نقطه ذخيره كنيد و سپس هر زماني كه خواست بتواند بازي را
از همان نقطه اي كه ذخيره كرده است ادامه دهيد . راه حل و طراحي شما براي اين مسئله چست و چگونه مي تواند باشد؟
يا يك مسئله ديگر : تصور كنيد شما در حال طراحي يك ف روشگاه الكترونيكي براي يك شركت هستيد . و يكي از ويژگيهاي در
خواست شده از طرف ذي النفعان سيستم اين است كه، هنگاميكه يك كاربر وارد فروشگاه مي شود و اجناس مورد نياز خود را به
سبد خريدش اضافه مي كند، اما قبل از اينكه سفارش خود را تائيد كند از فروشگاه خارج مي ش ود . سيستم بايد قابليت اين را
داشت باشد كه هنگام ورود بعدي همان كاربر، آيتم هاي موجود در سبد خريد قبلي را بازيابي كند و در سبد خريد مشتري قراد
دهد .
در هر دو مسئله بالا، كار ما ذخيره حالت موجود اشياء و سپس بازيابي آن حالت در صورت نياز هست . يك راه حل موجود و
است . كه نحوه عملكرد آنرا، برسي خواهيم كرد . Memento خوب براي مسائل بالا و شبيه آنها، الگوي
اين الگو بصورت زير اس ت: ،U ML نمودار
در اين الگو originator همانطوريكه در بالا اشاره شد، ما نياز داريم تا حالت يك شي را ذخيره و بازيابي كنيم، اين شي با نام
درخواست Client مشخص مي ش ود . اما نحوه ذخيره كردن وضعيت شي موجود به اين صورت است كه زمانيكه برنامه
تمام صفاتي را كه براي بازيابي حالتش نياز است را، ، (o riginator ) مي كند . اين شي originator ذ خيره كردن را از شي
از state ازسال ميكند (در نمودار مقدار صفت Client قرار مي دهد و آن را به Memento در يك شي ديگر به نام
را، Memento قرار مي گيرد .). ما نياز داريم تا اشياء از نوع Memento شي state در مقدار صفت ، originator شي
ايج اد Memento استفاده مي كنيم . زمانيكه يك شي ، caretaker نگهداري و مديريت كنيم . براي اينكار از كلاسي به نام
انجام مي undo اضافه مي شو د. وقتي كه يك عمل Caretaker مي شود، آن شي به مجموعه اشياء
انتخاب شود . بعد از انتخاب Memento همكاري مي كند تا يك شي ، (c lient ) با يك شي ديگر Caretaker شود شي
را فراخواني مي كند تا حالت انتخاب شده را بازيابي Originator شي setMemento آن شي متد ، Memento شي
كند.
51. الگوهاي طراحي
۵۱
فرضي كنيد شما در حال طراحي يك برنامه ويرايشگر متن هستيد، و يكي از نيازهاي مطرح شده توسط كاربران اين مورد است كه
وقتي آنها قسمتي از يك متن را كپي مي كنند، آن قسمت به يك ليست اضافه شود و نمايش داده شود . سپس زمانيكه كاربر به
يكي از متن هاي كپي شده نياز داشت، يكي از آنها از ليست انتخاب كند تا متن انتخاب شده به متن اصلي اضافه
. Microsoft Office Word برنامه clipboard دقيقا چيز شبيه .(p aste شو د (عمل
طراحي كنيم . در اين مثال شي كه ما نياز داريم، حالتش را ذخيره كنيم و ، Memento مي خواهيم اين خواسته را توسط الگوي
است . Clipboard سپس در صورت نياز بازيابي كنيم، شي
بيانگر حالت اين ، _Clipboard را پياده سازي مي كند . صفت Clipboard كه كد مربوط به originator كلاس
شي است و براي بازيابي آن بايد اين صفت را ذخيره كني م.
Public Class originator
Private _Clipboard As String
Public Property Clipboard() As String
Get
Return _Clipboard
End Get
Set(ByVal value As String)
_Clipboard = value
End Set
End Property
Public Function createMemento() As memento
Return New memento(_Clipboard)
End Function
Public Sub setMemento(ByVal _memento As memento)
_Clipboard = _memento.Clipboard
End Sub
End Class
به كار مي originator كه براي ذخيره اطلاعات مورد نياز براي يازيابي حالت يك نمونه از شي memento كلاس
رود .
Public Class memento
52. الگوهاي طراحي
۵۲
Private _Clipboard As String
Public Sub New(ByVal Data As String)
_Clipboard = Data
End Sub
Public Property Clipboard() As String
Get
Return _Clipboard
End Get
Set(ByVal value As String)
_Clipboard = value
End Set
End Property
End Class
به كار مي رود . در ا ينجا براي نگهداري اين memento براي نگهداري نمونه هاي مختلفي از كلاس caretaker كلاس
براي نمايش به كاربر برگشت داده memento مجموعه اشيايي ، list استفاد شده است . تو سط متد ArrayList نمونه ها از
مي شود . تا كاربر يكي از آنها را در صورت نياز انتخاب كند .
Public Class caretaker
Private memento As New ArrayList
Public Sub Add(ByVal _memento As memento)
memento.Add(_memento)
End Sub
Public Function List() As ArrayList
Return memento
End Function
End Class
بر روي آن قرار دارد تا ListBox استفاده شده است . كه يك كنترل FrmTest براي تست كلاس هاي بالا از يك فرم به نام
را نمايش دهد . تا كاربر بتواند حالت مورد نياز خود را از ميان آنها memento مقادير موجود در هر كدام از نمونه هاي شي
انتخاب كند .
Public Class FrmTest
53. الگوهاي طراحي
۵۳
Dim Ins As New originator
Dim List As New caretaker
Private Sub Form1_Load(ByVal sender As System.Object, ByVal eAs System.
EventArgs) Handles MyBase.Load
Ins.Clipboard = "Ali"
List.Add(Ins.createMemento())
Ins.Clipboard = "asd"
List.Add(Ins.createMemento())
Ins.Clipboard = "sdf"
List.Add(Ins.createMemento())
Me.ListBox1.DataSource = List.List
Me.ListBox1.DisplayMember = "Clipboard"
End Sub
Private Sub ListBox1_Click(ByVal sender As Object, ByVal e AsSystem.Eve
ntArgs) Handles ListBox1.Click
Ins.setMemento(List.List(Me.ListBox1.SelectedIndex))
End Sub
End Class
توجه : در پياده سازي مثال بالا، بعضي از قوانين شي گرايي ناديده گرفته شده است .( تصحيح به عهده دوستان)
54. الگوهاي طراحي
۵۴
Flyweight الگوي
تصور كنيد، شما مسئول طراحي يك برنامه هستيد كه قرار است براي هر كارمند يك سازمان، كارت ويزيتي مانند شكل زير چاپ
كند . سازمان مورد نظر، يك سازمان بسيار بزرگ با چند هزار كارمند مي باشد .
نام و نام خانوادگي
سمت
نام شركت
آدرس
اواين طراحي كه به ذهن مي تواند خطور كند، يك طراحي بسيار ساده است . يك كلاس به نام كارت ويزيت تعريف مي كنيم و
صفاتي را كه در كارت قرار دارند، به كلاس منتقل مي كنيم و يك متد چاپ هم براي چاپ كارت تعريف مي كنيم .
visitCard
Name
Title
Company
Address
print
ايجاد كند، يعني شما بايد چند هزار visitCard در اين صورت شما بايد به ازاء هر كارمند يك نمونه از كلاس
ايجاد كند . و اين مي تواند منابع زيادي از سيستم را مصرف كند . ولي شما با توجه به ساختار كارت متوجه مي visitCard شي
شود كه، نام شركت و آدرس براي تمام افراد يكي است . با اين آگاهي، آيا مي خواهيد تغييري در طراحي خود انجام بدهيد يا نه؟
يا شما مسئول طراحي يك برنامه پردازش متن هستيد . شكل زير، مي تواند يك نمودار كلاس ساده شده براي اين برنامه باشد.
55. الگوهاي طراحي
۵۵
از SetFont نماينگر يك كاراگتر در سند است . براي تغيير فونت يك كاراگتر مي توانيم متد Docchar هر نمونه از كلاس
خود استفاده خواهد كرد . container فراخواني كنيم . اگر فونت يك كاراگتر مشخص نشده با شد، از فونت Docchar شي
يك سند نمونه از اين برنامه را با طراحي بالا در نظر بگيريد، يك سند كه شامل چندين صفحه است، هر صفحه شامل چندين
خواهد بود و آن نيز شامل صد ها LineOfTextad شي پارگراف خواهد بود، و هر پارگراف شامل چندين شي
داشته باشيم كه، حافظه D ocChar خواهد بود، يعني در يك سند چند صفحه اي ممكن است هزار ها شي DocChar شي
زيادي را از سيستم مصرف خواهد كرد . شما براي كاهش مصرف حافظه، طراحي خود را به چه صورت تغيير مي دهيد؟
است . كه به بررسي آن خواهيم پرداخت . مشكل Flyweight يك راه حل كانديد و خوب براي حل هر دو مسئله بالا، الگوي
ما در هر دو مسئله بالا، توليد نمونه هاي بيش از حد از يك كلاس بود كه منجر به مصرف زياد منابع مي شد . يك شي شامل ۲ نوع
اطلاعات است :
اين نوع اطلاعات، اطلاعاتي هستند كه براي تمام نمونه هاي يك : (I ntrinsic Information) ۱ - اطلاعات داخلي
كلاس ثابت است . براي مثال، نام شركت و آدرس در مثال اول براي تمام كارمندان ثابت است .
اين نوع اطلاعات، اطلاعاتي هستند كه از نمونه اي به نمونه اي : (E xtrinsic Information ) ۲ - اطلاعات خارجي
ديگر فرق مي كند، يعني اشياء را از همديگر متمايز مي سازد . براي مثال، نام و سمت كارمند در مثال اول .
اين است كه، اطلاعات خارجي را، به خارج از كلاس منتقل كنيم و اين اطلاعات را به صورت Flyweight پيشنهاد الگوي
پارامتر هاي ورودي متدها دريافت كنيم، و تعداد نمونه ها را با به اشتراك گذاري آنها كاهش دهيم . نمودار كلاس اين الگو
بصورت زير است.
56. الگوهاي طراحي
۵۶
ها نمونه هاي به اشتراك گذاري يك كلاس هستند . چون اشياء به اشتراك ConcreteFlyweight ، در نمودار بالا هر كدام از
ها نبايد بطور مستقيم نمونه اي از آنرا ايجاد كنند . براي حل اين مشكل، Client ، گذاشته شده اند
را ايجاد مي كنيم . اين كلاس بايد بداند كه آيا نمونه اي از يك كلاس ايجاد شده است يا نه . FlyweightFactory كلاس
براي اين كار، ليستي از اشياء ايجاد شده را نگهداري مي كنيم كه اين اشياء از كلاس هاي مختلف توسط يك صفت كليد از هم
متمايز مي شوند . در مثال ۲ ما براي حل مشكل خود براي هر كاراكتر، يك كلاس،تعريف مي كنيم . كليد هر كدام از كلاس ها
همان، كاراكتري است كه نمايش خواهند داد . براي نمونه كلاس زير را در نظر بگيريد، كليد هر كلاس را
بخواهد نمونه اي از كلاس مورد نظرش را بسا زد، اين كلاس Client ذخيره مي كنيم، و وقتي كه Hashtable در يك
وجود دارد يا نه . اگر وجو نداشته باشد، نمونه اي از كلاس مورد نظر ايجاد Hashtable بررسي مي كند كه آيا اين كليد در
به آنرا برگشت مي دهد . (r eference ) مي كند، در غير اينصورت مرجعي
class CharacterFactory
{
private Hashtable characters = new Hashtable();
public Character GetCharacter(char key)
{
Character character = characters[key] as Character;
if (character == null)
{
switch (key)
{
case 'A': character = new CharacterA(); break;
case 'B': character = new CharacterB(); break;
//...
case 'Z': character = new CharacterZ(); break;
}
characters.Add(key, character);
}
return character;
}
}
57. الگوهاي طراحي
۵۷
Decorator الگوي
وارد فروشگاه مي شويد، غرفه ها را يكي يكي نگاه مي كنيد، بدنبال يك هديه مناسب براي يك شخص خاص هستي د. با زحمت و
وسواس زياد آنرا انتخاب مي كنيد و به فروشنده تحويل مي دهيد و مي گويد آنرا برايتان كادو و تزئين كند . فروشنده جعبه هاي
تزيئني مختلف را براي قرار دادن هديه براي شما نشان مي دهد تا يكي از آنها را انتخاب كنيد . شما جعبه مورد نظر را انتخاب مي
كنيد . و پيشنهاد مي كنيد در صورت امكان بعد از قرار دادن هديه شما و پيچيدن آن در كاغذ كادو، يك شاخه كل روي آن
تومان است و Y تومان است، قيمت جعبه X ، بچسباند . كار تمام مي شود . فروشنده مي گويد قيمت هديه اي كه انتخاب كرده ايد
تومان را پرداخت كنيد . X+Y+Z تومان است . شما بايد سر جمع Z فيمت شاخه گل
حالا فرض كنيد شما خريد، خود را تمام كرديد و هديه را به شخص مورد نظر خود تقديم كرديد . اما از طرف مسئولين همين
فروشگاه، شركت شما براي طراحي سيستم سفارش فروشگاه در نظر گرفته شده است . اين فرشگاه داراي كالاهاي متعدد كادويي
هست و همچنين داراي انواع زيادي از جعبه هاي تزئيني و وسايل براي تزئين كالاهاي مختلف اس ت. سيستم بايد قابليت اين را
داشته باشدكه قيمت كل را براي يك كالا با ساير وسايل تزئيني محاسبه كند . طراحي شما براي اين مسئله به چه صورت مي تواند
باشد؟
يك طراحي براي اين مسئله مي تواند به صورت زير باش د: يعني به اين صورت عمل شود كه، اگر مشتري، يك هديه را بدون
هيچ كالاي تزئيني ديگر خريد، يك نمونه از خود آن كلاس ايجاد شود و قيمت آن، توسط متد قيمت برگشت داده شو د. اگر
يك هديه نوع ۱ با جعبه ۱ خريداري شود، نمونه اي از هديه نوع ۱ با جعبه نوع ۱ ايجاد شود، و قيمت كل خريد بر گشت داده شود .
اما در اين حالت، اگر فروشگاه داراي دهها هديه و جعبه مختلف باشد، و شما هر كدام از تركيب هاي ممكن را بصورت يك
كلاس جداگانه تعريف كنيد، براي يك كار ساده شايد صدها كلاس داشته باشيد كه، بي شك مديريت و تغيير در هر كدام از
كلاس ها، هزينه زيادي را در بر خواهد داشت.
58. الگوهاي طراحي
۵۸
يك نوار رنگي نازك (b utton) برنامه هستيد، ترجيح مي دهيد كه اطراف بعضي از دكمه ها (U I) در حال طراحي اينترفيس
باشد . اما دكمه هاي كه شما استفاده كرده ايد، اين قابليت را ندارد . مي خواهيد خودتان اين قابليت را به دكمه ها اضافه كني د. شما
اين كار را به چه روشي انجام مي دهيد؟
است . Decorator طراحي هاي مختلفي را مي توان براي هر دو مسئله بالا ارائه داد . اما يك طراحي و راه حل خوب الگوي
در هر دو مثال بالا، ما مي خواهيم يك رفتار جديد را به يكي شي اضافه كنيم . ولي مي خواهيم بدون استفاده از وراثت اين رفتار را
به شي اضافه كنيم . اين الگو اجازه مي دهد، تا يك رفتار را بدون استفاده از وراثت و بصورت ديناميك به يك شي اضافه كنيم .
نمودار كلاس اين الگو بصورت زير اس ت:
در نمودار بالا مي باشد (شي دكمه ، ConcreteComponent شيي كه مي خواهيم رفتار جديدي را به آن اضافه كنيم، همان
اضافه مي كند . يكي ، ConcreteComponent در مثال دو م). و شيي كه رفتار جديد را به شي
ها، خواهد بود ( نوار نازك در مثال دوم ). اما اين رفتار جديد، چگونه اضافه مي شود؟ دقيقا به ConcreteDecorator از
همان صورتيكه ما هديه را در داخل جعبه قرار دادم . اينجا نيز ي ك نمونه از كلاس مورد نظر را در داخل كلاس ديگر قرار مي
دهيم و اجازه مي دهيم كلاس در برگيرنده بر روي آن كار كند . در پايين با مثال اول به بررسي كامل عملكرد اين الگو خواهيم
پرداخت .
در مثال اول، شما يك هديه، يك جعبه و يك گل مي خري د. فرضي كنيد مي خواهيم، مقدار كل را با
محاسبه كنيم : Decorator الگوي
در ابتدا يك شيي از كلاس هديه ۱ ايجاد مي كنيم . اين كلاس يك متد به نام قيمت براي محاسبه قيمت خود دارد.
59. الگوهاي طراحي
۵۹
هديه ۱ قيمت ()
سپس مشتري يك جعبه را انتخاب كرده بود، و فروشنده هديه را در داخل آن قرار داده بود . پس ما نيز همين كار را مي كنيم،
يعني فرضا نمونه اي از جعبه ۱ را ايجاد مي كنيم و شي هديه ايجاد شده را در داخل آن قرار مي دهيم . و هديه را با جعبه تزئين مي
كنيم .
جعبه ۱ قيمت ()
هديه ۱ قيمت ()
در آخر مشتري خواسته بود، يك گل بر روي هديه نصب شود . ما نيز همين كار را مي كنيم، يك نمونه از گل ايجاد مي كنيم . و
هديه را با آن تزئين مي كنيم .
گل قيم ت()
جعبه ۱ قيمت ()
هديه ۱ قيمت ()
حل مشتري مبلغ پرداختي را از فروشنده مي پرسد . پس ما بايد در اين نقطه قيمت را محاسبه كنيم . در ابتدا ما متد قيمت را از
بيروني ترين، تزئين كننده فراخواني مي كنيم . يعني در ابتدا متد قيمت را براي شي گل فراخواني مي كنيم . اين شي قيمت شي
بعدي يعني جعبه را فراخواني مي كند . و جعبه متد قيمت، هديه اصلي را فراخواني مي كند . در اين نقطه چون هديه يك شي
۳. سپس جعبه اس ت). قيمت خود را برگ شت مي دهد يعني ۰۰۰۰ C oncreteComponent تزئين كننده نيست (بلكه يك شي
قيمت خود را به قيمت برگشت داده شده توسط هديه، اضافه مي كند . و مجموع را برگشت مي دهديعني ۳۱۰۰۰ . در آخر نيز گل
مقدار خود را به مقدار برگشت داده شده اضافه مي كند و مجموع كل را برگشت مي دهد يعني ۳۳۰۰۰ . در پايين نحوه پياده سازي
ا لگو با همين آورده شده است .
(C omponent) Gift كلاس
Public MustInherit Class Gift
Public MustOverride Function Cost() As Double
End Class
Decorator كلاس
Public MustInherit Class Decorator
Inherits Gift
60. الگوهاي طراحي
۶۰
End Class
(C oncreteComponent ) Gift كلاس 1
Public Class Gift1
Inherits Gift
Public Overrides Function Cost() As Double
Return 30000
End Function
End Class
(C oncreteComponent ) Gift كلاس 2
Public Class Gift2
Inherits Gift
Public Overrides Function Cost() As Double
Return 10000
End Function
End Class
( ConcreteDecorator ) Box كلاس 1
Public Class Box1
Inherits Decorator
Private Gift As Gift
Public Sub New(ByVal Giftvar As Gift)
Gift = Giftvar
End Sub
Public Overrides Function Cost() As Double
Return 1000 + Gift.Cost
End Function
End Class
( ConcreteDecorator ) Box كلاس 2
Public Class Box2
Inherits Decorator
Private Gift As Gift
Public Sub New(ByVal Giftvar As Gift)
Gift = Giftvar
End Sub
Public Overrides Function Cost() As Double
Return 1500 + Gift.Cost()
61. الگوهاي طراحي
۶۱
End Function
End Class
(C oncreteDecorator ) Flower كلاس
Public Class Flower
Inherits Decorator
Private Gift As Gift
Public Sub New(ByVal Giftvar As Gift)
Gift = Giftvar
End Sub
Public Overrides Function Cost() As Double
Return 2000 + Gift.Cost
End Function
End Class
Main ماژول
Sub Main()
Dim Gift1 As Gift = New Gift1()
Gift1 = New Box1(Gift1)
Gift1 = New Flower(Gift1)
System.Console.WriteLine("Price = " & Gift1.Cost)
Dim Gift2 As Gift = New Gift2()
Gift2 = New Box1(Gift1)
Gift1 = New Flower(Gift1)
System.Console.WriteLine("Price = " & Gift1.Cost)
Console.ReadLine()
End Sub
62. الگوهاي طراحي
۶۲
Mediator الگوي
نمي دانم فارغ التحصيل شديد يا نه، اما همه ما در دوران دانشگاه همكلاسي ها و دوستان صميمي زيادي داريم كه، هميشه مي
خواهيم خبري از آنها داشته باشيم، اما بعدي از فارغ التحصيلي هزار و يك مشكل به سراغمان مي آي د. و اگر بخواهيم با تك و
تك آنها ارتباط داشته باشيم برايمان خيلي سخت خواهد بود همينطور براي آنها . اما تقريبا هميشه فردي هست كه، همه مي خواهند
با او ارتباط داشته باشند، پس مشكل حل شد ، پس فقط كافي است كه ما نيز با اين فرد تماس بگيرم تا خبري از همه بچه ها بدست
آوريم .
در دنياي نرم افزار هاي شي گرا نيز ، اشياء براي انجام دادن يك وظيفه با همديگر ارتباط دارند . اما همانند مثال بالا، هر چه تعداد
ارتباطات افزايش يابد، برنامه پيچيده تر خواهد شد و منجر خواهد شد كه نگهداري برنامه نيز سخت تر شود و قابليت استفاده
مجدد نيز كاهش يابد .
براي مثال فرم زير را در نظر بگيريد، اين فرم براي رزور يك اتاق مهماني در يك هتل استفاده مي شود، طرز عملكرد فرم در زير
توضيح داده شده است.
63. الگوهاي طراحي
۶۳
هنگاميكه پنجره براي اولين بار نمايش داده مي شود، فقط فيلد مربوط به تعداد مهمان ها و دكمه برگشت فعال است . كنترل هاي
تاريخ، ساعت شروع و ساعت اتمام زماني فعال مي شوند كه كاربر تعداد مهمان ها را وارد كند . اما فقط زمانهاي را مي تواند وارد
كند كه در آن موقع اتاقي با آن سايز موجود باشد . سپس گزينه سرويس ها فعال مي شود . اگر تعداد مهمان ها پاك شود، بايد تمام
گزينه ها پاك و غ ير فعال شوند .
ساعت شروع بايد كوچكتر از ساعت اتمام باشد .
هنگاميكه كاربر تعداد مهمانها و ساعت و تاريخ را وارد مي كند و يك نوع سرويس را انتخاب كرد، ليست غذا ها فعال مي شود .
با توجه به تاريخ، ساعت و نوع سرويس، ليست غذاهاي ارائه شده متفاوت خواهد بود .
هنگاميكه حداقل يك نوع غذا انتخاب شد، و داده ها ديگر معتبر بودند، دكمه رزور فعال مي شود .
شكل بالا، ارتباطات و روابط موجود بين اشياء روي فرم را نشان مي دهد . همانطوريكه داده مي شود، هر شي حداقل داراي ۲
وابستگي است . همانطوريكه در بالا نيز گفته شده، وابستگي باعث پيچيده شدن منطق برنامه خواهد شد و اين نگهداري سيستم را
64. الگوهاي طراحي
۶۴
مشكل تر خواهد كرد و قابليت استقاده مجدد را نيز كاهش خواهد داد . براي مثال تغيير در يكي از كلاس ها ممكن است، به تغيير
در ساير كلاس ها منجر شود . شما براي حل اين مشكل و كاهش تعداد وابستگي ها چه پيشنهادي داريد ؟
براي حل مشكل مي توانيم، مانند مثال اول عمل كنيم، يعني دوستي را ايجاد كنيم كه همه به جاي كساني كه مي خواهند با آنها
ارتباط برقرار كنند، فقط با او ارتباط برقرار كند . يعني در مثال دوم، ما يك كلاس جديد ايجاد كنيم كه، به جاي اينكه كلاس ها با
يكديگر بطور مستقيم ارتباط برقرار كنند، با كلاس جديد ارتباط بر قرار كنند و كلاس جديد مسئوليت ارتباط با كلاس ديگر را
نام دارد . در واقع اين كلاس مسئوليت، مديريت Mediator بعهده بگيريد . روشي كه براي حل مسئله مطرح شد، الگوي
شكل زير نحوه . Mediator وابستگي ها را بعهده مي گيرد . و با اين كار تمام اشياء، فق ط يك وابستگي دارند آن هم با كلاس
را نشان مي دهد . Mediator ارتباطات مثال ۲ را، بعد از اعمال شي
ارسال مي كند . و ، Mediator حالا زمانيكه يكي شي مي خواهد با شي ديگر ارتباط برقرار كند، پيام خود را به كلاس
همانند يك مسيرياب آن را به شي مورد نظر ارسال مي كن د. با استفاده از اين الگو مي توانيم به مزايا زير Mediator كلاس
دست يابيم :
۱. سادگي تغيير در برنامه : با استفاده از اين الگو وابستگي ميان كلاس هاي مختلف كاهش مي يابد و در اكثر موارد فقط با
و يا ايجاد زير كلاس هاي از اين كلاس، مي توانيم تغييرات مورد نظر را اعمال كنيم Mediator تغيير در كلاس
بدون اينكه تغييري در كلاس هاي ديگر بدهيم .
۲. افزايش قابليت استفاده مجدد : با كاهش وابستگي ميان كلاس، قابليت استفاده مجدد كلاس ها افزايش مي ياب د.
باعث كاهش پيچيدگي وابستگي بين ك لاس ها مي شود، اما اين پيچيدگي به درون Mediator ولي بايد توجه داشت كه كلاس
منتقل مي شود و ممكن است باعث شود كه تغيير آن مشكل شود. Mediator ساختار
65. الگوهاي طراحي
۶۵
Mediator الگو ي UML نمودار
تعريف مي كند كه اين اينترفيس توسط Colleague يك اينترفيس براي ارتباط با اشياء ، Mediator در نمودار بالا شي
كلاس ها، كلاس هاي هستند كه باهم ارتباط داشتند و Colleague پياده سازي مي شود . و ConcreteMediator كلاس
قرار داديم. Mediator ما اين ارتباط و وابستگي را از آنها جدا كردم و در كلاس
66. الگوهاي طراحي
۶۶
Composite الگوي
همانطوريكه روي صندلي نشسته ايد به بدن خود تان توجه كنيد و آنرا مورد بررسي قرار بدهيد، شايد بدن خود را به صورت
تركيبي از چندين شي مانند دست، پا، چشم و ... ببينيد . سپس با دست خود يك كتاب را برداريد و شروع به ورق زدن آن بكنيد،
مشاهده مي كنيد كه يك كتاب از ده ها صفحه تشكيل شده است و هر صفحه از چندين پارگراف و هر پار گراف از چندين سطر
كليك مي كنيد، دريواهاي كه كامپيوترتان داريد نشان داده مي شود، روي My Computer تشكيل شده است . روي آيكون
ها folder هاي آن دريوا نشان داده مي شود، سپس روي يكي از folder يكي از دريواها كليك مي كنيد، ليست فايل ها و
و يا فايل تشكيل شده است . در هر كدام از نمونه folder از چندين ، folder كليلك مي كند، مشاهده مي كند كه خود آن
هاي بالا، همانطوريكه ديديد يك شي ممكن شامل چندين شي ساده يا مركب ديگر نيز باشد، آن شي بايد بداند كه چگونه اين
اشياء را نگهداري و مديريت كند و هر چه تعداد اينگونه اشياء م ركب در سيستم افزايش يابد، سيستم پيچيده تر خواهد شد . شما
براي حل اين مشكل چه پيشنهادي داريد و چه راه حلي ارائه مي كنيد؟
اجازه بدهيد كار را با يك مثال ادامه دهيم . براي مثال فرض كنيد كه مي خواهيم يك برنامه ايجاد كنيم كه فايل سيستم ويندوز را
ها مي توانند از فايل ها Folder. و فايل داريم Folder شبيه سازي كند . در فايل سيستم ويندوز ما دو شي اصلي به نامه هاي
ها ديگر تشكيل شوند، در حاليكه فايل ها نمي توانند شامل مولفه اي ديگري از فايل سيستم باشند . براي اين مثال مي Folder يا
توان طراحي هاي گوناگوني را ارائه كرد . يك طرا حي مي تواند بدين صورت باشد كه، يك اينترفيس مشترك براي هر دو شي
موجود در مسئله تعريف كنيم، كه شامل متدهاي باشد كه در هر دو شي وجود دارند . شكل زير طراحي حاصل را نشان مي ده د.
را ايجاد كند . و با استفاده از FileSystemComponent مي تواند يك مجموعه از اشياء Clinet با اين طراحي
را FileSystemComponents نمونه هاي مختلفي از ، DirComponent شي ، addComponent مت د
اضافه كند . DirComponent به
را فراخواني getComponentSize بخواهد سايز هر كدام از اين اشياء را استخراج كند، به سادگي متد Clinet هنگاميكه
نبايد از نحوه محاسبه و عملياتي كه براي اندازه گيري سايز يك مولفه صورت مي گيرد آگاه باشد . در اين Client ، كند
به يك صورت رفتار مي كن د. DirComponent و FileComponent با هر دو شي client ، مورد
با هر دو ، getComponentSize در مورد متد مشترك Clinet
براي فراخواني متدهاي Clinet رفتار يكساني را دارد . اما DirComponent و FileComponent شي
نياز دارد كه دو شي را از همديگر تشخيص دهد، چونكه اين متدها فقط getComponent و addComponent مانند
نياز دارد تا نوع شي مورد نظر را براي فراخواني اين متدها client تعريف شده است . به همين دليل DirComponent براي
67. الگوهاي طراحي
۶۷
سر و كار دارد . براي بهبود اين طراحي بگونه اي كه نيازي به DirComponent چ ك كند تا مطمئن شود كه با يك نمونه از
تشخيص تفاوت بين دو شي وجود نداشته باشد، طراحي را به چه صورت تغيير مي دهد .
نيازي به تشخيص شي clinet ما مي خواهيم طراحي را بگونه اي تغيير دهيم كه
نداشته باشد، و با هر دو شي به يك صورت رفتار كن د. FileComponent از DirComponent مركب
را به اينترفيس getComponent و addComponent طراحي را مي توانيم به اين صورت تغيير دهيم كه، متدهاي
انتقال دهيم، و يك پياده سازي پيش فرض براي اين متدها انجام دهيم و اينترفيس FileSystemComponent مشترك
تغيير دهيم . پياده سازي پيش فرض براي اين متدها abstract را به يك كلاس FileSystemComponent مشترك
اين متدها را بازنويسي DirComponent هست و كار خاصي را انجام نمي دهد . اما كلاس FileComponent بخاطر
مجدد مي كند تا پياده سازي خاص خود را انجام دهد .
داراي يك پياده سازي پيش فرض ، FileSystemComponent با اين كار مشكل قبلي ما حل مي شود، چون كلاس پدر
نياز به كنترل نوع شي براي فراخواني clinet هست، و ديگر getComponent و addComponent براي متدهاي
اين دو متد ندارد .
اضافه كنيم، DirComponent را به كلاس removeComponent تصور كنيد كه مي خواهيم يك متد جديد با نام
نيز اضافه مي كنيم و يك پياده سازي پيش فرض براي اين متد در نظر مي FileComponent در اينصورت اين متد را به پدر
گيريم.
68. الگوهاي طراحي
۶۸
نام Composite با طراحي بالا ما توانستيم مشكل خود را حل كنيم، اما روشي كه براي غلبه بر مسئله استفاده كرديم، الگوي
دارد . ما در مواقعي از اين الگو استفاده مي كتيم كه يك شي پيچيده داريم و مي خواهيم آنرا به يك سلسله مراتب از اشياء كل و
قادر باشد تفاوت بين اشياء مركب client ، تجزيه كنيم . يا همانند مثال بالا (p artwhole
hierarchy ) جز
با همه اشياء موجود در ساختار مركب بصورت يكسان رفتار client و اشياء منفرد را ناديده بگيريد . و (D irComponent )
كند .
كلاس دياگرام اين الگو به صورت زير اس ت:
در مثال . FileComponent كلاس هاي هستند كه داراي فرزند نيستند مانند كلاس ، Leaf در دياگرام بالا كلاس
در مثال مي باشد . در اين كلاس رفتارهاي مربوط به مولفه هاي كه DirComponent كلاسي مانند ، Composite كلاس
داراي فرزند هستند تعريف مي گردد .
با ويژگيهاي كه در بالا اشاره شد هست. FileSystemComponent همان كلاس FileSystemComponent كلاس
69. الگوهاي طراحي
۶۹
Iterator الگوي
يا در ArrayList يكي شي مركب داريد، تمايل داريد اشياء تشكيل دهنده اين شي را چگونه ذخيره كنيد، در يك آرايه، در يك
يك ساختار ديگر . شما مي توانيد با توجه به علاقه و سبك كاري خود هر كدام از اين ساختمان داده ها را براي اينكار استفاده
كنيد . اما اجازه بدهيد روي مسئله را كمي تغ يير دهيم، يك كلاس ديگر نياز دارد به اشياء موجود در اين اشياء دسترسي داشته
باشد، براي اينكار حتما نياز خواهد داشت كه بداند شما اشياء را در اين شي به چه صورت ذخيره كرده اي د. پس براي غلبه به اين
مشكل شما نياز داريد، متدهاي را توسط شي مركب ارائه دهيد كه كلاس ه اي ديگر بدون اطلاع از نحوه ذخيره شدن اشياء، به
آنها دسترسي داشته باشند .
يك مسئله ديگر را در نظر بگيريد، ما چندين شي مركب يا ليستي از داده ها داريم، بعضي از كلاس ها نياز دارند تا به اشياء و داده
هاي موجود در اين اشياء يا ليست ها دسترسي داشته باشند، آيا مي ت وانيم طراحي خود را به صورتي ارائه دهيم كه يك كلاس، به
روشي مشابه به ليست اشياء يا داده ها دسترسي داشته باشد .
نام دارد . اين الگو يك اينترفيس تعريف مي كند كه Iterator الگوي كه مي توانيم براي حل اين مسئله بكار ببريم، الگوي
امكان دسترسي نرتيبي به عناصر يك مجمو عه را مي دهد . هر كلاس كه بخواهد به عناصر يك مجموعه دسترسي پيدا كند
از طريق اين اينترفيس عمل خواهد كرد كه مستقل از پياده سازي شي مركب و كلاسي كه اين اينترفيس را پياده سازي كرده است
خواهد بود .
تصور كنيد كه يك كتاب از چند فصل تشكيل شده است و هر فصل به عنوان ي ك شي در سيستم در نظر گرفته شده است، مي
خواهيم اسامي فصول اين يك كتاب را نمايش دهيم، براي اينكار ما نياز داريم تا به ليست فصول آن كتاب دسترسي داشته باشيم،
ما در ابتدا نياز داريم تا ي ك اينترفيس براي ، Iterator براي اينكار ما از الگوي بالا استفاده خواهيم كرد . طبق تعريف الگوي
اينكار تعريف كنيم . ما به متدهاي مانند بررسي اينكه عنصري بعدي در ليست وجود دارد يا نه، برگرداندن عنصر فعلي، برگرداندن
عنصر بعدي، و برگشت به عنصر اول . سپس ما نياز داريم تا اين اينترفيس را پياده سازي كنيم.
70. الگوهاي طراحي
۷۰
Iterator دياگرام الگوي
IIterator تعريف اينترفيس
Public Interface IIterator
Function FirstItem() As Object
Function NextItem() As Object
Function IsDone() As Boolean
Function CurrentItem() As Object
End Interface
IIterator پياده سازي اينترفيس
Public Class ConcreteIterator
Implements IIterator
Private List As New ArrayList
Private Current As Integer = 0
Public Sub New(ByVal VarList As ArrayList)
List = VarList
End Sub
Public Function CurrentItem() As Object ImplementsIIterator.CurrentItem
Return List(Current)
End Function
Public Function FirstItem() As Object ImplementsIIterator.FirstItem
Current = 0
If IsDone() Then
Return List(Current)
Else
Return Nothing
End If
End Function
Public Function IsDone() As Boolean Implements IIterator.IsDone
If Current >= List.Count Then
Return False
Else
Return True
End If
End Function
71. الگوهاي طراحي
۷۱
Public Function NextItem() As Object ImplementsIIterator.NextItem
Current += 1
If IsDone() Then
Return List(Current)
Else
Return Nothing
End If
End Function
End Class
Aggregate تعريف اينترفيس
Public Interface IAggregate
Function CreateIterator() As IIterator
End Interface
Book و كلاس Aggregate پياده سازي اينترفيس
Public Class Book
Implements IAggregate
Private _Name As String
Private _Chapters As New ArrayList
Public Property Name() As String
Get
Return _Name
End Get
Set(ByVal value As String)
_Name = value
End Set
End Property
Public Sub New()
End Sub
Public Sub New(ByVal VarName As String)
_Name = VarName
End Sub
72. الگوهاي طراحي
۷۲
Public Sub Add(ByVal Chapter As Chapter)
_Chapters.Add(Chapter)
End Sub
Public Function CreateIterator() As IIterator ImplementsIAggregate.CreateI
terator
Return New ConcreteIterator(_Chapters)
End Function
End Class
Chapter تعريف كلاس
Public Class Chapter
Private _Name As String
Public Property Name() As String
Get
Return _Name
End Get
Set(ByVal value As String)
_Name = value
End Set
End Property
Public Sub New()
End Sub
Public Sub New(ByVal VarName As String)
_Name = VarName
End Sub
End Class
نحوه استفاده
Dim Book As New Book("Book1")
Book.Add(New Chapter("Chapter 1"))
Book.Add(New Chapter("Chapter 2"))
Dim Iterator As IIterator = Book.CreateIterator
Dim Ins As Chapter = Iterator.FirstItem
While Iterator.IsDone
System.Console.WriteLine(Ins.Name)