مهدی عادلی فر
بنیانگذار توسینسو و برنامه نویس

آموزش الگوی های طراحی (Design Patterns) در سی شارپ

یکی از مباحث بسیار مهم در دنیای برنامه نویسی، الگوهای طراحی (Design Pattern) می باشند. در مطلب میخواهیم با زبان سی شارپ به بررسی الگوهای طراحی کاربردی و مهم بپردازیم و ببینیم دلیل استفاده از الگوهای طراحی (Design Patterns) چیست؟ با توجه به این که امروزه نرم افزارها بخش مهمی از زندگی بشر رو تشکیل داده اند و بسیاری از کارهای روز مره و محاسبات توسط نرم افزارها انجام می شود، طراحی و توسعه نرم افزار یکی از کار های مهم در جوامع کنونی است. به دلیل پویایی بیش از حد نرم افزار و تغییرات بسیار سریع تکنولوژی ها و نیازمندی های کاربران نرم افزار باید به گونه ای باشد که بتوان به آسانی آن را فهمید و تغییر داد. یکی از راه حل ها برای حل مشکلات گفته شده، الگوهای طراحی شی گرا (Object Oriented Design Pattern) می باشد.

دوره های شبکه، برنامه نویسی، مجازی سازی، امنیت، نفوذ و ... با برترین های ایران
سرفصل های این مطلب
  1. الگوی طراحی (Design Pattern) چیست؟
  2. معرفی الگوها
    1. مقدمه ای بر Object Oriented Design Patterns
    2. انواع الگوهای طراحی یا Design Pattern
    3. معرفی کوتاه انواع الگوریتم های طراحی
  3. Singleton و Adapter
    1. الگوی Singleton چیست؟
    2. ویژگی های الگوری Singleton
    3. الگوی Adapter چیست؟
    4. Adapter دوطرفه چیست؟
  4. الگوی Observer
    1. نقش الگوی Observer چیست؟
    2. تشریح الگوی Observer
    3. موارد استفاده الگوی Observer چیست؟
    4. ساختار الگوی Observer به چه شکل است؟
    5. کاربرد مدل های Push و Pull در چیست؟
    6. بررسی برخی از مسائل پیاده سازی الگوی Observer
    7. پیاده سازی الگوی Observer
  5. الگوی Iterator
    1. نقش الگوی Iterator چیست؟
    2. تشریح الگوی Iterator
    3. موارد استفاده الگوی Iterator
    4. ساختار الگوی Iterator
    5. پیاده سازی الگوی Iterator
  6. الگوی Command
    1. شرح الگوی Command
    2. طراحی الگوی Command
    3. پیاده سازی الگوی Command
    4. Command های دارای چند گیرنده (Multireceiver)
  7. الگوی Mediator
    1. شرح الگوی Mediator
    2. طراحی الگوی Mediator
    3. پیاده سازی الگوی Mediator
    4. استفاده از الگوی Mediator
  8. الگوی Memento
    1. اهداف الگوی Memento
    2. شرح الگوی Memento
    3. طراحی الگو (Design) Memento
    4. پیاده سازی الگوی Memento
  9. الگوی Strategy
    1. الگوی طراحی Strategy
    2. شرح الگوریتم الگوی Strategy
    3. طراحی الگوی Strategy
    4. پیاده سازی الگوی Strategy
    5. استفاده از الگوی Strategy
  10. آموزش دیزاین پترن (Design Patterns) قسمت 10 : الگوی Factory Method
    1. نقش الگوی Factory Method
    2. شرح الگوی Factory Method
    3. طراحی الگوی Factory Method
    4. پیاده سازی و مثال: فراهم کردن میوه آوکادو
    5. موارد استفاده الگوی Factory Method
  11. الگوی State
    1. شرح الگوی State
    2. طراحی الگوی State
    3. پیاده سازی الگوی State
    4. موارد استفاده الگوی State

این الگو ها به قدری مهم هستند که اگر کسی بخواهد در شرکتی به عنوان برنامه نویس استخدام شوند یکی از سوالاتی که در مصاحبه کاری از وی پرسیده می شود تسلط بر این الگوها می باشد. به دلیل این که منبع فارسی جامعی برای این مباحث وجود ندارد تصمیم گرفتم سری مقالات و آموزش الگوهای طراحی را به یاری خداوند شروع کنم.

سری مطالبی که به این منظور در سایت قرار خواهم داد این گونه خواهد بود که اول در قالب یک مقاله یک یا چند الگو را توضیح داده و مشکلات و چالش های آن را بررسی خواهم کرد سپس در قالب یک آموزش به توضیح و نحوه استفاده از الگوی مورد نظر را بیان می کنم.الگو هایی که در این سری مطالب بررسی می کنیم شامل الگوهای زیر می باشند:

  • الگوهای مطرح شده توسط Erich Gamma,Richard Helm, Ralph Johnson,John Vlissides که به اختصار gang of four شناخته می شوند.
  • الگوهای مطرح شده توسط Martin Fowler

در آموزش های گفته شده بیشتر از کد های C# استفاده خواهد شد ولی سعی می کنم کد های Java رو هم در کد ها بیاورم. برای درک کامل مطالبی که در این سری ارائه می شود لازم است که خوانندگان به مفاهیم شی گرایی و همچنین زبان مدل سازی uml آشنا باشند.از آنجایی که هیچ مطلبی خالی از اشکال نیست از دوستان خواهش می کنم که با نظرات خودشون بنده رو در این کار یاری کنند.حال به امید خدا شروع می کنیم.

الگوی طراحی (Design Pattern) چیست؟

برای شروع مقدمه ای از شی گرایی و نمودار های uml می گم تا در مطالب بعدی به الگوها می پردازم.ما در یک دنیای شی گرا زندگی می کنیم به گونه ای که خود شما یک شی هستید. شما با اشیا دیگر که ممکن است انسان، حیوان، و یا هرچیز دیگری ارتباط برقرار می کنید. همه اشیا دارای خصوصیاتی هستند. خود شما نیز دارای خصوصیاتی هستید مانند قد، وزن، رنگ مو و..... همچنین رفتار هایی از همه ی اشیا سر می زند یا بر روی اشیا رفتارهایی صورت می گیرد.

خود شما نیز دارای رفتارهایی مثل غذا خوردن و راه رفتن اجرا می کنید.اشیا در برنامه نویسی هم ساختارهایی هستند که دارای خصوصیات و رفتارهایی می باشند. که خصوصیات برای نگهداری داده های مربوط به شی مورد نظر مورد استفاده قرار می گیرندو و رفتار ها بر روی خصوصیات خود شی و یا خصوصیات اشیا دیگر عملی انجام می دهند. خصوصیات در برنامه نویسی شی گرا به نام های property,field شناخته می شوند و رفتارها با نام های method,function شناخته می شوند.

همه ی اشیا از مفهومی به نام کلاس ساخته می شوند که هر کلاس مشخص می کند که اشیائی که از آن کلاس ساخته می شوند باید چه خصوصیات و رفتارهایی داشته باشند. به طور مثال شما یک شی از کلاس انسان ساخته شده اید و خصوصیات و رفتارهایی را که انسان باید داشته باشد را دارید. اما خود کلاس یک مفهوم انتزاعی(abstract) است یعنی همانطور که انسان یک مفهوم است و وجود خارجی ندارد خود کلاس نیز وجود ندارد و برای درک آن باید شیئی که از آن ساخته شده را دید.

یکی از مفاهیمی که در برنامه نویسی شی گرا به آن برمی خوریم مفهوم کپسوله سازی(Encapsulation) است. همانطور که گفته شد همه ی اشیا دارای خصوصیات و رفتارهایی هستند که برخی بر همه آشکار است و برخی دیگر از دید دیگران مخفی هستند. به این مفهوم کپسوله سازی می گویند که یکی از مفاهیم بسیار مهم شی گرایی می باشد و باعث می شود اطلاعاتی برای دیگر اشیا آشکار شود که مورد نیاز آنها است و باقی اطلاعات از دید کاربران مخفی است و همینطور باعث بالا رفتن امنیت داده ها می شود.

همینطور با استفاده از کپسوله سازی می توان بر چگونگی استفاده از خصوصیات اشیا نیز نظارت داشت.از مفاهیم دیگر در برنامه نویسی شی گرا وراثت(inheritance) می باشد که به توضیح آن می پردازیم. اگر شما خود را به عنوان یک شی در نظر بگیرید که از کلاس انسان ساخته شده باشید. این نکته بدیهی است که انسان یک موجود زنده است، زیرا خواص و رفتارهای موجودات زنده را دارد مانند تنفس و تغذیه و رشد و ترمیم.

در مفاهیم شی گرایی می گوییم کلاس انسان کلاس موجودات زنده را به ارث می برد یا کلاس انسان از کلاس موجودات زنده مشتق می شود. در برنامه نویسی شی گرا نیز وراثت به این شکل است و کلاس ها مانند دنیای واقعی به شکل سلسله مراتبی ساخته می شوند که یک کلاس می تواند از کلاس دیگر مشتق شود و خصوصیات و متدهای کلاس پدر را داشته باشد.

یکی از مفاهیم دیگر در شی گرایی چندریختی(polymorphism) می باشد که به این معنی است که همه ی کلاس های مشتق شده از یک کلاس خاص می توانند یک رفتار خاص را به گونه ای که مورد نظر خودشان است پیاده سازی کنند. برای مثال تصور کنید در کلاس حیوانات پستانداری که در خشکی زندگی می کنند عمل راه رفتن وجود دارد ولی حیوانی مانند ببر بر روی پنجه راه می رود و حیوانی مانند اسب بر روی سم راه می رود.

هر دو کلاس اسب و ببر عمل راه رفتن را انجام می دهند ولی این متد را هر کدام به شکل گوناگون پیاده سازی کرده اند.مفهومی که در شی گرایی به وفور از آن استفاده می شود مفهوم انتزاع(abstraction) است. تلویزیون خانه خود را در نظر بگیرید . این دستگاه دارای یک کنترل از راه دور است که با استفاده از آن می توان اعمالی را برروی تلویزیون مثل روشن و خاموش کردن انجام داد

ولی لازم نیست که کاربران درباره ی چگونگی ارتباط کنترل از راه دور با دستگاه و نحوه پردازش امواج توسط کنترل اطلاعی داشته باشد و فقط باید روش کارکردن با آن را بلد باشد. دربرنامه نویسی نیز کلاس ها و اشیا بسیاری هستند که ما باید فقط روش کارکردن با آنها را بلد باشیم و نیازی نیست که بدانیم چگونه طراحی شده و از چه الگوریتم هایی بهره گرفته اند و فقط می توانیم از خصوصیات و ویژگی های مرتبط آنها اطلاع داشته باشیم.

اینترفیس(Interface): در زبان هایی مثل C#, Java اینترفیس ها بیان کننده ی قوانینی هستنند که اگر کلاسی بخواهد از اینترفیس مورد نظر استفاده کند مجبور است که همه ی قوانین را اجرا می کند. این قوانین شامل خصوصیات کلاس و نوع آن و همچنین شامل متدها و نوع برگشتی و تعداد آرگومان های آن است. نکته ای که وجود دارد این است که اینترفیس هیچ کدام از این متدها رو پیاده سازی نمی کند و خصوصیات را مقدار دهی نمی کند و فقط مشخص می کند که کلاس های مشتق شده باید این ویژگیها را حتما باید داشته باشند.

اینترفیس ها در داخل الگوهای طراحی بسیار کاربرد دارد که در مقالات بعدی بیشتر آشنا خواهیم شد. قسمت های گفته شده تنها یک معرفی ساده و خیلی کوتاه از مفاهیم شی گرایی می باشد که لازم بود برای وارد شدن به مبحث الگوهای طراحی گفته شوند. در ادامه به معرفی چند نمودار UML می پردازیم که در شرح الگوهای طراحی از آنها بسیار استفاده خواهیم نمود. نمودار کلاس (class diagram) این نمودار همه ی کلاس ها و خصوصیات و متدهای آنها و همچنین ارتباط بین کلاس ها و نوع این ارتباط ها را نشان می دهد.

با سلام به همه همراهان و اعضای محترم انجمن تخصصی فناوری اطلاعات ایران. با توجه به این که امروزه نرم افزارها بخش مهمی از زندگی بشر رو تشکیل داده اند و بسیاری از کارهای روز مره و محاسبات توسط نرم افزارها انجام می شود، طراحی و توسعه نرم افزار یکی از کار های مهم در جوامع کنونی است. به دلیل پویایی بیش از حد نرم افزار و تغییرات بسیار سریع تکنولوژی ها و نیازمندی های کاربران نرم افزار باید به گونه ای باشد که بتوان به آسانی آن را فهمید و تغییر داد. یکی از راه حل ها برای حل مشکلات گفته شده، الگوهای طراحی شی گرا (Object Oriented Design Pattern) می باشد. این الگو ها به قدری مهم هستند که اگر کسی بخواهد در شرکتی به عنوان برنامه نویس استخدام شوند یکی از سوالاتی که در مصاحبه کاری از وی پرسیده می شود تسلط بر این الگوها می باشد. به دلیل این که منبع فارسی جامعی برای این مباحث وجود ندارد تصمیم گرفتم سری مقالات و آموزش الگوهای طراحی را به یاری خداوند شروع کنم.سری مطالبی که به این منظور در سایت قرار خواهم داد این گونه خواهد بود که اول در قالب یک مقاله یک یا چند الگو را توضیح داده و مشکلات و چالش های آن را بررسی خواهم کرد سپس در قالب یک آموزش به توضیح و نحوه استفاده از الگوی مورد نظر را بیان می کنم.الگو هایی که در این سری مطالب بررسی می کنیم شامل الگوهای زیر می باشند:

* الگوهای مطرح شده توسط Erich Gamma,Richard Helm, Ralph Johnson,John Vlissides که به اختصار gang of four شناخته می شوند.
* الگوهای مطرح شده توسط Martin Fowler

در آموزش های گفته شده بیشتر از کد های C# استفاده خواهد شد ولی سعی می کنم کد های Java رو هم در کد ها بیاورم. برای درک کامل مطالبی که در این سری ارائه می شود لازم است که خوانندگان به مفاهیم شی گرایی و همچنین زبان مدل سازی uml آشنا باشند.از آنجایی که هیچ مطلبی خالی از اشکال نیست از دوستان خواهش می کنم که با نظرات خودشون بنده رو در این کار یاری کنند.حال به امید خدا شروع می کنیم.

!! مقدمه 
برای شروع مقدمه ای از شی گرایی و نمودار های uml می گم تا در مطالب بعدی به الگوها می پردازم.ما در یک دنیای شی گرا زندگی می کنیم به گونه ای که خود شما یک شی هستید. شما با اشیا دیگر که ممکن است انسان، حیوان، و یا هرچیز دیگری ارتباط برقرار می کنید. همه اشیا دارای خصوصیاتی هستند. خود شما نیز دارای خصوصیاتی هستید مانند قد، وزن، رنگ مو و..... همچنین رفتار هایی از همه ی اشیا سر می زند یا بر روی اشیا رفتارهایی صورت می گیرد. خود شما نیز دارای رفتارهایی مثل غذا خوردن و راه رفتن اجرا می کنید.اشیا در برنامه نویسی هم ساختارهایی هستند که دارای خصوصیات و رفتارهایی می باشند. که خصوصیات برای نگهداری داده های مربوط به شی مورد نظر مورد استفاده قرار می گیرندو و رفتار ها بر روی خصوصیات خود شی و یا خصوصیات اشیا دیگر عملی انجام می دهند. خصوصیات در برنامه نویسی شی گرا به نام های property,field شناخته می شوند و رفتارها با نام های method,function شناخته می شوند.

همه ی اشیا از مفهومی به نام کلاس ساخته می شوند که هر کلاس مشخص می کند که اشیائی که از آن کلاس ساخته می شوند باید چه خصوصیات و رفتارهایی داشته باشند. به طور مثال شما یک شی از کلاس انسان ساخته شده اید و خصوصیات و رفتارهایی را که انسان باید داشته باشد را دارید. اما خود کلاس یک مفهوم انتزاعی(abstract) است یعنی همانطور که انسان یک مفهوم است و وجود خارجی ندارد خود کلاس نیز وجود ندارد و برای درک آن باید شیئی که از آن ساخته شده را دید.یکی از مفاهیمی که در برنامه نویسی شی گرا به آن برمی خوریم مفهوم کپسوله سازی(Encapsulation) است. همانطور که گفته شد همه ی اشیا دارای خصوصیات و رفتارهایی هستند که برخی بر همه آشکار است و برخی دیگر از دید دیگران مخفی هستند. به این مفهوم کپسوله سازی می گویند که یکی از مفاهیم بسیار مهم شی گرایی می باشد و باعث می شود اطلاعاتی برای دیگر اشیا آشکار شود که مورد نیاز آنها است و باقی اطلاعات از دید کاربران مخفی است و همینطور باعث بالا رفتن امنیت داده ها می شود.

همینطور با استفاده از کپسوله سازی می توان بر چگونگی استفاده از خصوصیات اشیا نیز نظارت داشت.از مفاهیم دیگر در برنامه نویسی شی گرا وراثت(inheritance) می باشد که به توضیح آن می پردازیم. اگر شما خود را به عنوان یک شی در نظر بگیرید که از کلاس انسان ساخته شده باشید. این نکته بدیهی است که انسان یک موجود زنده است، زیرا خواص و رفتارهای موجودات زنده را دارد مانند تنفس و تغذیه و رشد و ترمیم. در مفاهیم شی گرایی می گوییم کلاس انسان کلاس موجودات زنده را به ارث می برد یا کلاس انسان از کلاس موجودات زنده مشتق می شود. در برنامه نویسی شی گرا نیز وراثت به این شکل است و کلاس ها مانند دنیای واقعی به شکل سلسله مراتبی ساخته می شوند که یک کلاس می تواند از کلاس دیگر مشتق شود و خصوصیات و متدهای کلاس پدر را داشته باشد.

یکی از مفاهیم دیگر در شی گرایی چندریختی(polymorphism) می باشد که به این معنی است که همه ی کلاس های مشتق شده از یک کلاس خاص می توانند یک رفتار خاص را به گونه ای که مورد نظر خودشان است پیاده سازی کنند. برای مثال تصور کنید در کلاس حیوانات پستانداری که در خشکی زندگی می کنند عمل راه رفتن وجود دارد ولی حیوانی مانند ببر بر روی پنجه راه می رود و حیوانی مانند اسب بر روی سم راه می رود. هر دو کلاس اسب و ببر عمل راه رفتن را انجام می دهند ولی این متد را هر کدام به شکل گوناگون پیاده سازی کرده اند.مفهومی که در شی گرایی به وفور از آن استفاده می شود مفهوم انتزاع(abstraction) است. تلویزیون خانه خود را در نظر بگیرید . این دستگاه دارای یک کنترل از راه دور است که با استفاده از آن می توان اعمالی را برروی تلویزیون مثل روشن و خاموش کردن انجام داد ولی لازم نیست که کاربران درباره ی چگونگی ارتباط کنترل از راه دور با دستگاه و نحوه پردازش امواج توسط کنترل اطلاعی داشته باشد و فقط باید روش کارکردن با آن را بلد باشد. دربرنامه نویسی نیز کلاس ها و اشیا بسیاری هستند که ما باید فقط روش کارکردن با آنها را بلد باشیم و نیازی نیست که بدانیم چگونه طراحی شده و از چه الگوریتم هایی بهره گرفته اند و فقط می توانیم از خصوصیات و ویژگی های مرتبط آنها اطلاع داشته باشیم.

اینترفیس(Interface): در زبان هایی مثل C#, Java اینترفیس ها بیان کننده ی قوانینی هستنند که اگر کلاسی بخواهد از اینترفیس مورد نظر استفاده کند مجبور است که همه ی قوانین را اجرا می کند. این قوانین شامل خصوصیات کلاس و نوع آن و همچنین شامل متدها و نوع برگشتی و تعداد آرگومان های آن است. نکته ای که وجود دارد این است که اینترفیس هیچ کدام از این متدها رو پیاده سازی نمی کند و خصوصیات را مقدار دهی نمی کند و فقط مشخص می کند که کلاس های مشتق شده باید این ویژگیها را حتما باید داشته باشند. اینترفیس ها در داخل الگوهای طراحی بسیار کاربرد دارد که در مقالات بعدی بیشتر آشنا خواهیم شد. قسمت های گفته شده تنها یک معرفی ساده و خیلی کوتاه از مفاهیم شی گرایی می باشد که لازم بود برای وارد شدن به مبحث الگوهای طراحی گفته شوند. در ادامه به معرفی چند نمودار UML می پردازیم که در شرح الگوهای طراحی از آنها بسیار استفاده خواهیم نمود. نمودار کلاس (class diagram) این نمودار همه ی کلاس ها و خصوصیات و متدهای آنها و همچنین ارتباط بین کلاس ها و نوع این ارتباط ها را نشان می دهد.

||http://tosinso.com/files/get/077149fa-090c-4988-9abd-2c1b2e198ab9||

مهمترین عنصر در این نمودار عنصر کلاس است که به شکل مستطیل است که دارای سه قسمت می باشد: در بالای این شکل اسم کلاس آورده شده است و در قسمت Attributes خصوصیات کلاس و در قسمت Operations متدهای کلاس آورده می شود.ارتباط بین کلاس ها با خطوطی مشخص می شوند که هر کدام دارای مفهوم خاصی می باشد. یکی از ارتباط های مهم، ارتباط وراثت می باشد که به این شکل نشان داده می شود.

||http://tosinso.com/files/get/f9511325-4694-47fc-bdd6-7fe791c15e57||

در شکل بالا کلاس های Teacherو Student از کلاس Person ارث بری می کنند. توجه داشته باشید که کلاس ها می توانند از یک اینترفیس نیز ارث بری داشته باشند. اینترفیس ها به شکل زیر در نمودار کلاس نشان داده می شوند.

||http://tosinso.com/files/get/42bcc39e-4c00-4d00-85aa-9905481418f7||

قسمت های گفته شده پیش نیاز هایی برای ورود به مباحث الگوهای طراحی شی گرا بود. در بیان این مطالب سعی شده بود که به شکل ساده و ملموس گفته شود. دوستان توجه داشته باشند که این مطالب فقط یک مقدمه بودند و به صورت اجمالی و مختصر گفته شده اند. به امید خدا مطالبی را در تکمیل مباحث گفته شده خواهم آورد.*ITPRO باشید*


نویسنده : مهدی عادلی
منبع : |جزیره برنامه نویسی وب سایت توسینسو::https://programming.tosinso.com|
هرگونه نشر و کپی برداری بدون ذکر منبع و نام نویسنده دارای اشکال اخلاقی می باشد.

مهمترین عنصر در این نمودار عنصر کلاس است که به شکل مستطیل است که دارای سه قسمت می باشد: در بالای این شکل اسم کلاس آورده شده است و در قسمت Attributes خصوصیات کلاس و در قسمت Operations متدهای کلاس آورده می شود.ارتباط بین کلاس ها با خطوطی مشخص می شوند که هر کدام دارای مفهوم خاصی می باشد. یکی از ارتباط های مهم، ارتباط وراثت می باشد که به این شکل نشان داده می شود.

با سلام به همه همراهان و اعضای محترم انجمن تخصصی فناوری اطلاعات ایران. با توجه به این که امروزه نرم افزارها بخش مهمی از زندگی بشر رو تشکیل داده اند و بسیاری از کارهای روز مره و محاسبات توسط نرم افزارها انجام می شود، طراحی و توسعه نرم افزار یکی از کار های مهم در جوامع کنونی است. به دلیل پویایی بیش از حد نرم افزار و تغییرات بسیار سریع تکنولوژی ها و نیازمندی های کاربران نرم افزار باید به گونه ای باشد که بتوان به آسانی آن را فهمید و تغییر داد. یکی از راه حل ها برای حل مشکلات گفته شده، الگوهای طراحی شی گرا (Object Oriented Design Pattern) می باشد. این الگو ها به قدری مهم هستند که اگر کسی بخواهد در شرکتی به عنوان برنامه نویس استخدام شوند یکی از سوالاتی که در مصاحبه کاری از وی پرسیده می شود تسلط بر این الگوها می باشد. به دلیل این که منبع فارسی جامعی برای این مباحث وجود ندارد تصمیم گرفتم سری مقالات و آموزش الگوهای طراحی را به یاری خداوند شروع کنم.سری مطالبی که به این منظور در سایت قرار خواهم داد این گونه خواهد بود که اول در قالب یک مقاله یک یا چند الگو را توضیح داده و مشکلات و چالش های آن را بررسی خواهم کرد سپس در قالب یک آموزش به توضیح و نحوه استفاده از الگوی مورد نظر را بیان می کنم.الگو هایی که در این سری مطالب بررسی می کنیم شامل الگوهای زیر می باشند:

* الگوهای مطرح شده توسط Erich Gamma,Richard Helm, Ralph Johnson,John Vlissides که به اختصار gang of four شناخته می شوند.
* الگوهای مطرح شده توسط Martin Fowler

در آموزش های گفته شده بیشتر از کد های C# استفاده خواهد شد ولی سعی می کنم کد های Java رو هم در کد ها بیاورم. برای درک کامل مطالبی که در این سری ارائه می شود لازم است که خوانندگان به مفاهیم شی گرایی و همچنین زبان مدل سازی uml آشنا باشند.از آنجایی که هیچ مطلبی خالی از اشکال نیست از دوستان خواهش می کنم که با نظرات خودشون بنده رو در این کار یاری کنند.حال به امید خدا شروع می کنیم.

!! مقدمه 
برای شروع مقدمه ای از شی گرایی و نمودار های uml می گم تا در مطالب بعدی به الگوها می پردازم.ما در یک دنیای شی گرا زندگی می کنیم به گونه ای که خود شما یک شی هستید. شما با اشیا دیگر که ممکن است انسان، حیوان، و یا هرچیز دیگری ارتباط برقرار می کنید. همه اشیا دارای خصوصیاتی هستند. خود شما نیز دارای خصوصیاتی هستید مانند قد، وزن، رنگ مو و..... همچنین رفتار هایی از همه ی اشیا سر می زند یا بر روی اشیا رفتارهایی صورت می گیرد. خود شما نیز دارای رفتارهایی مثل غذا خوردن و راه رفتن اجرا می کنید.اشیا در برنامه نویسی هم ساختارهایی هستند که دارای خصوصیات و رفتارهایی می باشند. که خصوصیات برای نگهداری داده های مربوط به شی مورد نظر مورد استفاده قرار می گیرندو و رفتار ها بر روی خصوصیات خود شی و یا خصوصیات اشیا دیگر عملی انجام می دهند. خصوصیات در برنامه نویسی شی گرا به نام های property,field شناخته می شوند و رفتارها با نام های method,function شناخته می شوند.

همه ی اشیا از مفهومی به نام کلاس ساخته می شوند که هر کلاس مشخص می کند که اشیائی که از آن کلاس ساخته می شوند باید چه خصوصیات و رفتارهایی داشته باشند. به طور مثال شما یک شی از کلاس انسان ساخته شده اید و خصوصیات و رفتارهایی را که انسان باید داشته باشد را دارید. اما خود کلاس یک مفهوم انتزاعی(abstract) است یعنی همانطور که انسان یک مفهوم است و وجود خارجی ندارد خود کلاس نیز وجود ندارد و برای درک آن باید شیئی که از آن ساخته شده را دید.یکی از مفاهیمی که در برنامه نویسی شی گرا به آن برمی خوریم مفهوم کپسوله سازی(Encapsulation) است. همانطور که گفته شد همه ی اشیا دارای خصوصیات و رفتارهایی هستند که برخی بر همه آشکار است و برخی دیگر از دید دیگران مخفی هستند. به این مفهوم کپسوله سازی می گویند که یکی از مفاهیم بسیار مهم شی گرایی می باشد و باعث می شود اطلاعاتی برای دیگر اشیا آشکار شود که مورد نیاز آنها است و باقی اطلاعات از دید کاربران مخفی است و همینطور باعث بالا رفتن امنیت داده ها می شود.

همینطور با استفاده از کپسوله سازی می توان بر چگونگی استفاده از خصوصیات اشیا نیز نظارت داشت.از مفاهیم دیگر در برنامه نویسی شی گرا وراثت(inheritance) می باشد که به توضیح آن می پردازیم. اگر شما خود را به عنوان یک شی در نظر بگیرید که از کلاس انسان ساخته شده باشید. این نکته بدیهی است که انسان یک موجود زنده است، زیرا خواص و رفتارهای موجودات زنده را دارد مانند تنفس و تغذیه و رشد و ترمیم. در مفاهیم شی گرایی می گوییم کلاس انسان کلاس موجودات زنده را به ارث می برد یا کلاس انسان از کلاس موجودات زنده مشتق می شود. در برنامه نویسی شی گرا نیز وراثت به این شکل است و کلاس ها مانند دنیای واقعی به شکل سلسله مراتبی ساخته می شوند که یک کلاس می تواند از کلاس دیگر مشتق شود و خصوصیات و متدهای کلاس پدر را داشته باشد.

یکی از مفاهیم دیگر در شی گرایی چندریختی(polymorphism) می باشد که به این معنی است که همه ی کلاس های مشتق شده از یک کلاس خاص می توانند یک رفتار خاص را به گونه ای که مورد نظر خودشان است پیاده سازی کنند. برای مثال تصور کنید در کلاس حیوانات پستانداری که در خشکی زندگی می کنند عمل راه رفتن وجود دارد ولی حیوانی مانند ببر بر روی پنجه راه می رود و حیوانی مانند اسب بر روی سم راه می رود. هر دو کلاس اسب و ببر عمل راه رفتن را انجام می دهند ولی این متد را هر کدام به شکل گوناگون پیاده سازی کرده اند.مفهومی که در شی گرایی به وفور از آن استفاده می شود مفهوم انتزاع(abstraction) است. تلویزیون خانه خود را در نظر بگیرید . این دستگاه دارای یک کنترل از راه دور است که با استفاده از آن می توان اعمالی را برروی تلویزیون مثل روشن و خاموش کردن انجام داد ولی لازم نیست که کاربران درباره ی چگونگی ارتباط کنترل از راه دور با دستگاه و نحوه پردازش امواج توسط کنترل اطلاعی داشته باشد و فقط باید روش کارکردن با آن را بلد باشد. دربرنامه نویسی نیز کلاس ها و اشیا بسیاری هستند که ما باید فقط روش کارکردن با آنها را بلد باشیم و نیازی نیست که بدانیم چگونه طراحی شده و از چه الگوریتم هایی بهره گرفته اند و فقط می توانیم از خصوصیات و ویژگی های مرتبط آنها اطلاع داشته باشیم.

اینترفیس(Interface): در زبان هایی مثل C#, Java اینترفیس ها بیان کننده ی قوانینی هستنند که اگر کلاسی بخواهد از اینترفیس مورد نظر استفاده کند مجبور است که همه ی قوانین را اجرا می کند. این قوانین شامل خصوصیات کلاس و نوع آن و همچنین شامل متدها و نوع برگشتی و تعداد آرگومان های آن است. نکته ای که وجود دارد این است که اینترفیس هیچ کدام از این متدها رو پیاده سازی نمی کند و خصوصیات را مقدار دهی نمی کند و فقط مشخص می کند که کلاس های مشتق شده باید این ویژگیها را حتما باید داشته باشند. اینترفیس ها در داخل الگوهای طراحی بسیار کاربرد دارد که در مقالات بعدی بیشتر آشنا خواهیم شد. قسمت های گفته شده تنها یک معرفی ساده و خیلی کوتاه از مفاهیم شی گرایی می باشد که لازم بود برای وارد شدن به مبحث الگوهای طراحی گفته شوند. در ادامه به معرفی چند نمودار UML می پردازیم که در شرح الگوهای طراحی از آنها بسیار استفاده خواهیم نمود. نمودار کلاس (class diagram) این نمودار همه ی کلاس ها و خصوصیات و متدهای آنها و همچنین ارتباط بین کلاس ها و نوع این ارتباط ها را نشان می دهد.

||http://tosinso.com/files/get/077149fa-090c-4988-9abd-2c1b2e198ab9||

مهمترین عنصر در این نمودار عنصر کلاس است که به شکل مستطیل است که دارای سه قسمت می باشد: در بالای این شکل اسم کلاس آورده شده است و در قسمت Attributes خصوصیات کلاس و در قسمت Operations متدهای کلاس آورده می شود.ارتباط بین کلاس ها با خطوطی مشخص می شوند که هر کدام دارای مفهوم خاصی می باشد. یکی از ارتباط های مهم، ارتباط وراثت می باشد که به این شکل نشان داده می شود.

||http://tosinso.com/files/get/f9511325-4694-47fc-bdd6-7fe791c15e57||

در شکل بالا کلاس های Teacherو Student از کلاس Person ارث بری می کنند. توجه داشته باشید که کلاس ها می توانند از یک اینترفیس نیز ارث بری داشته باشند. اینترفیس ها به شکل زیر در نمودار کلاس نشان داده می شوند.

||http://tosinso.com/files/get/42bcc39e-4c00-4d00-85aa-9905481418f7||

قسمت های گفته شده پیش نیاز هایی برای ورود به مباحث الگوهای طراحی شی گرا بود. در بیان این مطالب سعی شده بود که به شکل ساده و ملموس گفته شود. دوستان توجه داشته باشند که این مطالب فقط یک مقدمه بودند و به صورت اجمالی و مختصر گفته شده اند. به امید خدا مطالبی را در تکمیل مباحث گفته شده خواهم آورد.*ITPRO باشید*


نویسنده : مهدی عادلی
منبع : |جزیره برنامه نویسی وب سایت توسینسو::https://programming.tosinso.com|
هرگونه نشر و کپی برداری بدون ذکر منبع و نام نویسنده دارای اشکال اخلاقی می باشد.

در شکل بالا کلاس های Teacherو Student از کلاس Person ارث بری می کنند. توجه داشته باشید که کلاس ها می توانند از یک اینترفیس نیز ارث بری داشته باشند. اینترفیس ها به شکل زیر در نمودار کلاس نشان داده می شوند.

با سلام به همه همراهان و اعضای محترم انجمن تخصصی فناوری اطلاعات ایران. با توجه به این که امروزه نرم افزارها بخش مهمی از زندگی بشر رو تشکیل داده اند و بسیاری از کارهای روز مره و محاسبات توسط نرم افزارها انجام می شود، طراحی و توسعه نرم افزار یکی از کار های مهم در جوامع کنونی است. به دلیل پویایی بیش از حد نرم افزار و تغییرات بسیار سریع تکنولوژی ها و نیازمندی های کاربران نرم افزار باید به گونه ای باشد که بتوان به آسانی آن را فهمید و تغییر داد. یکی از راه حل ها برای حل مشکلات گفته شده، الگوهای طراحی شی گرا (Object Oriented Design Pattern) می باشد. این الگو ها به قدری مهم هستند که اگر کسی بخواهد در شرکتی به عنوان برنامه نویس استخدام شوند یکی از سوالاتی که در مصاحبه کاری از وی پرسیده می شود تسلط بر این الگوها می باشد. به دلیل این که منبع فارسی جامعی برای این مباحث وجود ندارد تصمیم گرفتم سری مقالات و آموزش الگوهای طراحی را به یاری خداوند شروع کنم.سری مطالبی که به این منظور در سایت قرار خواهم داد این گونه خواهد بود که اول در قالب یک مقاله یک یا چند الگو را توضیح داده و مشکلات و چالش های آن را بررسی خواهم کرد سپس در قالب یک آموزش به توضیح و نحوه استفاده از الگوی مورد نظر را بیان می کنم.الگو هایی که در این سری مطالب بررسی می کنیم شامل الگوهای زیر می باشند:

* الگوهای مطرح شده توسط Erich Gamma,Richard Helm, Ralph Johnson,John Vlissides که به اختصار gang of four شناخته می شوند.
* الگوهای مطرح شده توسط Martin Fowler

در آموزش های گفته شده بیشتر از کد های C# استفاده خواهد شد ولی سعی می کنم کد های Java رو هم در کد ها بیاورم. برای درک کامل مطالبی که در این سری ارائه می شود لازم است که خوانندگان به مفاهیم شی گرایی و همچنین زبان مدل سازی uml آشنا باشند.از آنجایی که هیچ مطلبی خالی از اشکال نیست از دوستان خواهش می کنم که با نظرات خودشون بنده رو در این کار یاری کنند.حال به امید خدا شروع می کنیم.

!! مقدمه 
برای شروع مقدمه ای از شی گرایی و نمودار های uml می گم تا در مطالب بعدی به الگوها می پردازم.ما در یک دنیای شی گرا زندگی می کنیم به گونه ای که خود شما یک شی هستید. شما با اشیا دیگر که ممکن است انسان، حیوان، و یا هرچیز دیگری ارتباط برقرار می کنید. همه اشیا دارای خصوصیاتی هستند. خود شما نیز دارای خصوصیاتی هستید مانند قد، وزن، رنگ مو و..... همچنین رفتار هایی از همه ی اشیا سر می زند یا بر روی اشیا رفتارهایی صورت می گیرد. خود شما نیز دارای رفتارهایی مثل غذا خوردن و راه رفتن اجرا می کنید.اشیا در برنامه نویسی هم ساختارهایی هستند که دارای خصوصیات و رفتارهایی می باشند. که خصوصیات برای نگهداری داده های مربوط به شی مورد نظر مورد استفاده قرار می گیرندو و رفتار ها بر روی خصوصیات خود شی و یا خصوصیات اشیا دیگر عملی انجام می دهند. خصوصیات در برنامه نویسی شی گرا به نام های property,field شناخته می شوند و رفتارها با نام های method,function شناخته می شوند.

همه ی اشیا از مفهومی به نام کلاس ساخته می شوند که هر کلاس مشخص می کند که اشیائی که از آن کلاس ساخته می شوند باید چه خصوصیات و رفتارهایی داشته باشند. به طور مثال شما یک شی از کلاس انسان ساخته شده اید و خصوصیات و رفتارهایی را که انسان باید داشته باشد را دارید. اما خود کلاس یک مفهوم انتزاعی(abstract) است یعنی همانطور که انسان یک مفهوم است و وجود خارجی ندارد خود کلاس نیز وجود ندارد و برای درک آن باید شیئی که از آن ساخته شده را دید.یکی از مفاهیمی که در برنامه نویسی شی گرا به آن برمی خوریم مفهوم کپسوله سازی(Encapsulation) است. همانطور که گفته شد همه ی اشیا دارای خصوصیات و رفتارهایی هستند که برخی بر همه آشکار است و برخی دیگر از دید دیگران مخفی هستند. به این مفهوم کپسوله سازی می گویند که یکی از مفاهیم بسیار مهم شی گرایی می باشد و باعث می شود اطلاعاتی برای دیگر اشیا آشکار شود که مورد نیاز آنها است و باقی اطلاعات از دید کاربران مخفی است و همینطور باعث بالا رفتن امنیت داده ها می شود.

همینطور با استفاده از کپسوله سازی می توان بر چگونگی استفاده از خصوصیات اشیا نیز نظارت داشت.از مفاهیم دیگر در برنامه نویسی شی گرا وراثت(inheritance) می باشد که به توضیح آن می پردازیم. اگر شما خود را به عنوان یک شی در نظر بگیرید که از کلاس انسان ساخته شده باشید. این نکته بدیهی است که انسان یک موجود زنده است، زیرا خواص و رفتارهای موجودات زنده را دارد مانند تنفس و تغذیه و رشد و ترمیم. در مفاهیم شی گرایی می گوییم کلاس انسان کلاس موجودات زنده را به ارث می برد یا کلاس انسان از کلاس موجودات زنده مشتق می شود. در برنامه نویسی شی گرا نیز وراثت به این شکل است و کلاس ها مانند دنیای واقعی به شکل سلسله مراتبی ساخته می شوند که یک کلاس می تواند از کلاس دیگر مشتق شود و خصوصیات و متدهای کلاس پدر را داشته باشد.

یکی از مفاهیم دیگر در شی گرایی چندریختی(polymorphism) می باشد که به این معنی است که همه ی کلاس های مشتق شده از یک کلاس خاص می توانند یک رفتار خاص را به گونه ای که مورد نظر خودشان است پیاده سازی کنند. برای مثال تصور کنید در کلاس حیوانات پستانداری که در خشکی زندگی می کنند عمل راه رفتن وجود دارد ولی حیوانی مانند ببر بر روی پنجه راه می رود و حیوانی مانند اسب بر روی سم راه می رود. هر دو کلاس اسب و ببر عمل راه رفتن را انجام می دهند ولی این متد را هر کدام به شکل گوناگون پیاده سازی کرده اند.مفهومی که در شی گرایی به وفور از آن استفاده می شود مفهوم انتزاع(abstraction) است. تلویزیون خانه خود را در نظر بگیرید . این دستگاه دارای یک کنترل از راه دور است که با استفاده از آن می توان اعمالی را برروی تلویزیون مثل روشن و خاموش کردن انجام داد ولی لازم نیست که کاربران درباره ی چگونگی ارتباط کنترل از راه دور با دستگاه و نحوه پردازش امواج توسط کنترل اطلاعی داشته باشد و فقط باید روش کارکردن با آن را بلد باشد. دربرنامه نویسی نیز کلاس ها و اشیا بسیاری هستند که ما باید فقط روش کارکردن با آنها را بلد باشیم و نیازی نیست که بدانیم چگونه طراحی شده و از چه الگوریتم هایی بهره گرفته اند و فقط می توانیم از خصوصیات و ویژگی های مرتبط آنها اطلاع داشته باشیم.

اینترفیس(Interface): در زبان هایی مثل C#, Java اینترفیس ها بیان کننده ی قوانینی هستنند که اگر کلاسی بخواهد از اینترفیس مورد نظر استفاده کند مجبور است که همه ی قوانین را اجرا می کند. این قوانین شامل خصوصیات کلاس و نوع آن و همچنین شامل متدها و نوع برگشتی و تعداد آرگومان های آن است. نکته ای که وجود دارد این است که اینترفیس هیچ کدام از این متدها رو پیاده سازی نمی کند و خصوصیات را مقدار دهی نمی کند و فقط مشخص می کند که کلاس های مشتق شده باید این ویژگیها را حتما باید داشته باشند. اینترفیس ها در داخل الگوهای طراحی بسیار کاربرد دارد که در مقالات بعدی بیشتر آشنا خواهیم شد. قسمت های گفته شده تنها یک معرفی ساده و خیلی کوتاه از مفاهیم شی گرایی می باشد که لازم بود برای وارد شدن به مبحث الگوهای طراحی گفته شوند. در ادامه به معرفی چند نمودار UML می پردازیم که در شرح الگوهای طراحی از آنها بسیار استفاده خواهیم نمود. نمودار کلاس (class diagram) این نمودار همه ی کلاس ها و خصوصیات و متدهای آنها و همچنین ارتباط بین کلاس ها و نوع این ارتباط ها را نشان می دهد.

||http://tosinso.com/files/get/077149fa-090c-4988-9abd-2c1b2e198ab9||

مهمترین عنصر در این نمودار عنصر کلاس است که به شکل مستطیل است که دارای سه قسمت می باشد: در بالای این شکل اسم کلاس آورده شده است و در قسمت Attributes خصوصیات کلاس و در قسمت Operations متدهای کلاس آورده می شود.ارتباط بین کلاس ها با خطوطی مشخص می شوند که هر کدام دارای مفهوم خاصی می باشد. یکی از ارتباط های مهم، ارتباط وراثت می باشد که به این شکل نشان داده می شود.

||http://tosinso.com/files/get/f9511325-4694-47fc-bdd6-7fe791c15e57||

در شکل بالا کلاس های Teacherو Student از کلاس Person ارث بری می کنند. توجه داشته باشید که کلاس ها می توانند از یک اینترفیس نیز ارث بری داشته باشند. اینترفیس ها به شکل زیر در نمودار کلاس نشان داده می شوند.

||http://tosinso.com/files/get/42bcc39e-4c00-4d00-85aa-9905481418f7||

قسمت های گفته شده پیش نیاز هایی برای ورود به مباحث الگوهای طراحی شی گرا بود. در بیان این مطالب سعی شده بود که به شکل ساده و ملموس گفته شود. دوستان توجه داشته باشند که این مطالب فقط یک مقدمه بودند و به صورت اجمالی و مختصر گفته شده اند. به امید خدا مطالبی را در تکمیل مباحث گفته شده خواهم آورد.*ITPRO باشید*


نویسنده : مهدی عادلی
منبع : |جزیره برنامه نویسی وب سایت توسینسو::https://programming.tosinso.com|
هرگونه نشر و کپی برداری بدون ذکر منبع و نام نویسنده دارای اشکال اخلاقی می باشد.

قسمت های گفته شده پیش نیاز هایی برای ورود به مباحث الگوهای طراحی شی گرا بود. در بیان این مطالب سعی شده بود که به شکل ساده و ملموس گفته شود. دوستان توجه داشته باشند که این مطالب فقط یک مقدمه بودند و به صورت اجمالی و مختصر گفته شده اند. به امید خدا مطالبی را در تکمیل مباحث گفته شده خواهم آورد.

معرفی الگوها

در بخش قبل مطالبی در باره ی شی گرایی و مفاهیم کلی آورده شد و در این بخش به شکل خاص به الگوهای طراحی خواهیم پرداخت و در بخش های بعد به شرح یک یا دو الگو می پردازیم.

مقدمه ای بر Object Oriented Design Patterns

طراحی برنامه های شی گرا به خودی خود سخت است و طراحی برنامه های شی گرایی که قابل استفاده مجدد هم باشند از آن نیز سخت تر است. قابلیت استفاده مجدد برای برنامه های نوشته شده بسیار مهم است. نکته ای که طراحان خبره برای حل یک مسئله می­دانند اینست که نباید هر مسئله را از اول حل کرد. یعنی نباید برای حل آن از ابتدای کار شروع کنیم. بلکه باید با توجه به ابزار موجود و استفاده مجدد از آنها این کار انجام شود.

آنها وقتی که یک راه­حل مناسب را یافتند، آنرا دفعات زیادی استفاده خواهند کرد. این تجربه، یکی از مسائلی است که آنها را خبره می­کند. در نتیجه شما الگوهایی تکراری از کلاس­ها و اشیاء مرتب را در بسیاری از سیستمهای شئ­گرا خواهید دید. هر الگو یک مشکل خاص را در طراحی نرم­افزار حل می­کند و باعث می­شود که طراحی شئ­گرای ما انعطاف­پدیرتر، زیباتر و در نهایت قابل استفاده مجدد باشد.این الگو ها به طراحان کمک می­کنند که با مبنا قرار دادن تجربیات گذشته در طرح های جدید طرحهای موفق را مجددا استفاده نمایند. طراحی که با این الگو ها آشنایی بیشتری دارد، می­تواند بلافاصله برای طراحی راه حل یک مسئله جدید، آنها را بکار گیرد.

بدون اینکه مجبور به کشف مجدد آنها باشد. شباهت ها می­توانند به تجسم نقاط مشترک بین الگوهای ،کمک کنند.الگوهای طراحی، استفاده مجدد از طرح ها و معماری های موفق را آسانتر می کنند. بیان نمودن تکنیک های اثبات شده و کارا بصورت الگوهای طراحی، آنها را برای برنامه نویسان سیستم های جدید بسیار قابل دسترس تر می کند. الگوهای طراحی به شما کمک می کنند تا از بین انتخاب های موجود، طرح هایی را بکار گیرید

که قابلیت استفاده مجدد از سیستم شما را بالا می برند و از انتخاب طرح هایی که قابلیت استفاده مجدد را کاهش می دهند، جلوگیری می کنند. بصورت ساده تر؛ الگوهای طراحی به طراح کمک می کنند تا طرح صحیح را سریعتر بیابد. هر الگو مسأله اي را شرح مي دهد که در محيط ما به طور مکرر رخ داده ، و سپس راه حل اصلي مسأله را شرح مي دهد ، به گونه اي که مي توانيد بيش از يک ميليون بار از اين راه حل استفاده کنيد ، بدون اين که دوبار آن را به يک طريق اجرا کنيد.

انواع الگوهای طراحی یا Design Pattern

به دليل اين که الگوهاي طراحي فراواني وجود دارد نياز به شيوه اي جهت سازماندهي آن ها داريم . اين بخش الگوهاي طراحي را به گونه اي طبقه بندي مي کند که بتوانيم به خانواده هاي الگوهاي مربوطه ارجاع نمائيم . اين طبقه بندي به شما کمک مي کند الگوهاي موجود را سريعتر بياموزيد.

طبقه بندی الگوهای طراحی

ما با دو ضابطه الگوهاي طراحي را طبقه بندي مي کنيم . ضابطه ي اول که هدف ناميده مي شود منعکس کننده کار الگو است . الگوها مي توانند داراي اهداف آفرينش(creational) ، ساختاري(structural) يا رفتاري(behavioral) مي باشند . الگوهاي آفرينش به فرآيند ايجاد اشیا مربوط مي شوند . الگوهاي ساختاري به ترکيب کلاس ها يا اشیا مي پردازند . الگوهاي رفتاري شيوه هايي را که در آن ها کلاس ها يا اشیا تعامل مي کنند را مشخص کرده و وظایف را توزيع مي کنند .

ضابطه دوم که حوزه(Scope) ناميده مي شود و مشخص مي کند که الگو در مرحله نخست در کلاس ها يا اشیا به کار مي رود . الگوهاي کلاس به روابط ميان کلاس ها و کلاس هاي فرعي آن ها مي پردازد . اين روابط به گونه اي از طريق وراثت مستقر مي گردند که در زمان کامپايل ايستا باشند . الگوهاي شی به روابط اشیا مي پردازند که مي تواند در حين اجرا تغيير کنند و پوياتر هستند . تقريبا کليه الگوها تا حدي از وراثت استفاده مي کنند . توجه داشته باشيد اغلب الگوها در حوزه شی قرار مي گيرند .

الگوهاي کلاس آفرينش بخشي از آفرینش اشیا را به کلاس هاي فرعي واگذار مي کنند ، در حاليکه الگوها ي شی آفرينشي آن را با شی ديگري تعويض مي کنند. الگوهاي کلاس ساختاري از وراثت جهت ساختن کلاس ها استفاده مي کنند، در حاليکه الگوهاي شی ساختاري به شرح راه هايي جهت نصب اشیا مي پردازد. الگوهاي کلاس رفتاري از وراثت جهت توصيف الگوريتم ها و جريان کنترل استفاده مي کنند ، در حاليکه الگوهاي شی رفتاري شرح مي دهند که چگونه يک گروه از اشیا جهت انجام وظيفه اي که هيچ شی منفردي قابل به انجام آن نيست مشارکت مي کنند.

شيوه هاي ديگري جهت سازماندهي الگوها وجود دارد. اغلب بعضي از الگوها با يکديگر استفاده مي شوند . به عنوان مثال ، اغلب Composite با Iterator يا Visitor استفاده مي شود . بعضي الگوها جايگزين هستند : اغلب الگو ي Prototype جايگزين Abstract Factory است . بعضي الگوها با وجود آن که داراي هدف هاي متفاوتي هستند به طراحي مشابه منجر مي شوند .

به عنوان مثال ، نمودارهاي ساختار Composite و Decorator مشابه هستند .روشن است که راههاي بسياري براي سازماندهي الگوهاي طراحي وجود دارد. داشتن چندين راه براي فکر کردن درباره الگوها ، بينش شما را در مورد اين که آنها چه کاري انجام مي دهند، چگونه مقايسه مي شوند و چه وقت به کار گرفته مي شوند، عميق تر مي کند.

ارتباط بین الگوهای طراحی

معرفی کوتاه انواع الگوریتم های طراحی

  1. Abstract Factory: خانواده هایی از اشیا که اعضای خانواده به یکدیگر مرتبط هستند را تولید می کند.
  2. Adapter: اینترفیسی ایجاد می کند که کلاس هایی که با هم مرتبط نیستند بتوانند با یکدیگر کار کنند.
  3. Bridge" جدا ساختن قسمت پیاده سازی از قسمت انتزاعی یک کلاس برای این که دو طرف بتوانند به راحتی و مستقلا تغییر کنند.
  4. Builder: ساخت يک شی پيجيده را به گونه اي از نمايش آن مجزا مي کند که همان فرآيند ساخت مي تواند نمایش های متفاوتی ایجاد کند.
  5. Chain of Responsibility: در قالب یک زنجیره از اشیا به درخواست کاربر پاسخ می دهد.
  6. Command: مشخص می کند که یک عملیات(operation) چگونه انجام شود و انجام آن ها را مدیریت می کند.
  7. Composite: اشیا را در ساختارهاي درختي ترکيب مي کند. Composite به کاربران اجازه مي دهد با اشیا منفرد و اشیا ترکيبي به طور يکسان برخورد کنند.
  8. Decorator: مسؤوليت هاي اضافي را به طور ديناميک به يک شی ضميمه مي کند . Decorator ها جايگزيني انعطاف پذير جهت طبقه بندي فرعي براي توسعه عملکرد مهيا مي کنند .
  9. Facade: اینترفیسي يکنواخت براي مجموعه ميانجي هاي موجود در يک کلاس فرعي مهيا مي کند . نماي خارجي، اینترفیس سطح بالاتري را تعريف مي کند که استفاده از سيستم فرعي را ساده تر مي کند .
  10. Factory Method: يک اینترفیس جهت ايجاد يک شی تعيين مي کند ، ولي اجازه مي دهد کلاس هاي فرعي تصميم بگيرند کدام کلاس را معرفي کند
  11. Flyweight: زمانی استفاده می شود که تعداد اشیا بسیار زیاد باشد و مدیریت آنها سخت باشد.
  12. Interpreter: جهت تعریف گرامرهای یک زبان و تفسیر جملات استفاده می شود که تنها در طراحی کامپایلرها کاربرد دارد.
  13. Iterator: شيوه اي جهت دسترسي به عناصر يک شی بهم پيوسته به طور متوالي تدارک مي بيند بدون اين که نمايش موجود را دچار مخاطره کند .
  14. Mediator: شیئی را تعيين مي کند که چگونگي تعامل يک مجموعه اشیا را در یک محفظه قرار مي دهد. همچنین باعث می شود که اشیا به طور دو به دو کمتر با هم ارتباط داشته باشند و پدیده ی coupling کمتر شود.
  15. Memento: حالت دروني يک شی را به گونه اي دقيق ذخیره می کند که بعدا بتوان شی را به اين حالت بازگرداند.
  16. Observer: يک وابستگي يک به چند ميان اشیا را به گونه اي تعريف مي کند که هنگامي که يک شی تغيير کند کليه موارد وابسته به آن متوجه شده و به طور خودکار بهنگام سازي شوند .
  17. Prototype: برای ساخت و کپی کردن شیئی جدید که خواص شی اصلی را داشته باشد.
  18. Proxy: براي شی ديگر يک جانشين يا جاي گيرنده فراهم مي کند تا چگونگي دسترسي به آن را کنترل کند .
  19. Singleton: تضمين مي کند که يک کلاس فقط يک نمونه داشته باشد ، و يک نمونه ي کلي جهت دسترسي به آن را مهيا کند .
  20. State: به يک شی اجازه مي دهد هنگامي که حالت دروني آن تغيير کرد رفتار خود را عوض کند . به نظر مي رسد که شی کلاس خود را عوض مي کند .
  21. Strategy: يک خانواده از الگوريتم ها را تعريف کرده ، هر يک را در پوشش قرار داده و آن ها را قابل تعویض مي سازد . استراتژي اجازه مي دهد الگوريتم به طور مستقل از کاربران که از آن استفاد مي کنند متفاوت باشد .
  22. Template Method: اسکلت بندي الگوريتم در يک عمليات را تعريف کرده ، پیاده سازی بعضي مراحل را یه کلاس های فرعی می سپارد. همچنین به کلاس هاي فرعي مجال مي دهد بعضي مراحل يک الگوريتم را بدون تغيير ساختار الگوريتم دوباره تعريف کند .
  23. Visitor: ويزيتور به شما مجال مي دهد عمليات جديد را بدون تغيير کلاس هاي عناصري که در آن کار مي کند تغيير دهيد .

مطالب گفته شده مقدمه ای برای آشنایی با الگوهای طراحی بود و در بخش های بعدی به مطالعه دقیق هر کدام از الگوهای گفته شده و موارد استفاده آنها خواهیم پرداخت.

Singleton و Adapter

در بخش های قبل در مباحثی کلی درباره ی شی گرایی و الگوهای طراحی مطرح شد و از این بخش به بعد به تک تک الگو ها می پردازیم و هرکدام را توضیح خواهیم داد. در این بخش به الگوهای Singleton و Adapter می پردازیم که نسبتا الگوهای ساده تری هستند می پردازیم.

الگوی Singleton چیست؟

این الگو یکی از الگوهای سازنده (creational) است و در ساختن اشیا از کلاس ها کاربرد دارد. این الگو یکی از معروف ترین الگوهای مطرح شده توسط Gang of Four است.

  • نکته: کلمه کاربر که در این سری مقالات استفاده می شود به کلاس هایی اطلاق می شود که از کلاس مورد بحث استفاده می کنند و منظور تنها کاربر انسانی نیست و ممکن است که یک زیرسیستم یا یک کلاس و یا حتی تابع main برنامه باشد.

حالتی را در نظر بگیرید که کلاسی دارید که می خواهید در کل برنامه خود فقط یک شی از این کلاس ساخته شود و اجازه ساخته شدن نمونه جدید به استفاده کنندگان از این کلاس داده نشود. این عمل در مواقعی بسیار لازم و ضروری است. به طور مثال حالتی را درنظر بگیرید که در برنامه کلاسی وجود دارد که واسط تنظیمات برنامه است یعنی برنامه هنگام لود شدن تنظیمات خود را در آن بارگزاری می کند.

حال اگر این شی یک شی در کل برنامه یکتا نباشد و هر بخش از برنامه که بخواهد تنظیمات را بخواند و یا تغییری در آن ایجاد کند مجبور باشد که یک شی جدید از کلاس تنظیمات بسازد مدیریت این اشیا مشکل می شود و همچنین باعث نابه سامانی در تنظیمات خواهد شد. راه حل این مسئله این است که از همان اول کلاس به گونه ای تعریف شود که اجازه ساختن نمونه جدید به کاربران ندهد و تنها کاربران بتوانند یک نمونه از کلاس به وجود آورند.

اگر به برخی از قسمت های سیستم عامل ویندوز هم نگاهی بکنیم متوجه می شویم که چنین مکانیزمی در آن تعبیه شده است مثلاً یک سیستم فایل برای مدیریت فایل ها وجود دارد و یا با وجود این که ممکن است چندین پرینتر به کامپیوتر متصل باشد ولی فقط یک printer spooler در سیستم وجود دارد.

برای به وجود آوردن چنین مکانیزمی شاید اولین راه حل این باشد که یک شی سراسری در کل برنامه تعریف شده و هروقت که برنامه ای بخواهد از این کلاس استفاده کند از شی سراسری تعریف شده استفاده کند. اما مشکلی که این راه حل دارد این است که این راه حل مانع ساخت شی جدید از کلاس نمی شود. یک راه حل بهتر این است که خود کلاس را مسئول این کار قرار دهیم که مواظب باشد که یک نمونه بیشتر نداشته باشد. این کار را الگوی Singleton انجام می دهد.

روش کار این الگو به این صورت است که یک نمونه از خود کلاس در داخل کلاس ساخته می شود و هر وقت که کلاس های دیگر خواستند از این کلاس استفاده کنند تنها می توانند به این نمونه ساخته شده دسترسی داشته باشند و نمی توانند از کلاس نمونه سازی کنند.ساختار این الگو به این شکل است:

ساختار الگوی Singleton

همانطور که در شکل می بینید یک فیلد به نام instance داریم که از خود کلاس است و این فیلد تنها الگویی که قرار است ساخته شود را در خود نگهداری می کند. سازنده(constructor) این کلاس از نوع private بوده بنابراین نمی توان از این کلاس یک نمونه جدید توسط عملگر new ایجاد کرد. تنها راه ساختن یک نمونه از این کلاس فراخوانی متد GetInstance است.

ویژگی های الگوری Singleton

این الگو باعث می شود که دسترسی به نمونه های کلاس کنترل شود و تعداد خاص از نمونه ها ایجاد شود.با استفاده از این الگو نیاز به ساختن متغیر های سراسری در فضای namespace کمتر شده و از اشغال فضای namespace توسط متغیرهای سراسری جلوگیری می کند. کد پیاده سازی این الگو در زبان C# به شکل زیر است

  public sealed class Singleton
    {
       private Singleton()
        {
        }
        private readonly static Singleton instance=new Singleton();
        public static Singleton UniqueInstance { get { return instance; } }
    }

همانطور که درکد مشاهده می شود یک بار یک نمونه از کلاس ساخته می شود و تنها راه دسترسی به کلاس استفاده از ویژگی UniqueInstance می باشد که نمونه ساخته شده را برمی گرداند. در این نوع پیاده سازی از همان ابتدا یک نمونه از کلاس ساخت شده است و استفاده می شود ولی می توان این نمونه را وقتی ساخت که درخواستی برای اولین باربه کلاس ارسال شود که به این شیوه Lazy instantiate گفته می شود. کد این روش به شکل زیر است.

 public class LazySingleton
    {
        private LazySingleton(){}
        private static LazySingleton instance;

        public static LazySingleton UniqueInstance
        {
            get { return instance!=null?instance:new LazySingleton();}
        }

    }

کدی که آورده شده است تا حدی می تواند هدف این الگو را که ساخته شدن یک نمونه از کلاس باشد را برآورده کند ولی اگر برنامه دارای چند thread باشد ممکن است در مواردی بیشتر از یک نمونه از کلاس ساخته شود که در اصطلاح گفته می شود برنامه Thread Safe نیست که به جای کد بالا از کد پایین استفاده می کنیم.

    public class Singleton
    {
        private Singleton(){}

        class SingletonCreator
        {
            static SingletonCreator()
            {
            }
            internal static readonly Singleton UniqueInstance = new Singleton(); 
        }

        public static Singleton UniqueInstance
        {
            get { return SingletonCreator.UniqueInstance; }
        }
    }

در کد بالا از یک کلاس داخلی برای ساخت نمونه از کلاس استفاده می شود که علاوه بر Thread safe بودن خاصیت Lazy instatiate هم دارد.حال اگر نیاز باشد که از یک خانواده کلاس ها تنها یک نمونه ایجاد شود پیاده سازی این الگوی کمی متفاوت تر خواهد شد. برای مثال تصور کنید که یک کلاس میوه دارید که از آن کلاس های دیگری مانند سیب و پرتقال مشتق شده اند و لازم است که در برنامه فقط یک عدد میوه وجود داشته باشد یعنی اگر یک سیب وجود دارد دیگر نتوان میوه ی دیگری(چه سیب و چه پرتقال) ایجاد کرد. به منظور پیاده سازی چنین روشی به شکل زیر عمل می کنیم.

 public  class SingleFruit
        {
            public string name;
            protected SingleFruit()
            { }
            protected static  SingleFruit Instance ;
            public static SingleFruit UniqueInstance
            {
                get { return Instance; }
            }
        }

        public class SingleApple : SingleFruit
        {
           
            private SingleApple()
            {
                name = "Apple";
            }
            public static SingleFruit UniqueInstance
            {
                get { return Instance != null ? Instance :Instance= new SingleApple(); }
            }
        }

        public class SingleOrange : SingleFruit
        {
            private SingleOrange()
            {
                name = "Orange";
            }
            public static SingleFruit UniqueInstance
            {
                get { return Instance != null ? Instance :Instance= new SingleOrange(); }
            }

        }

با توجه به کد بالا اگر به کلاس های فرزندان مقداردهی نشده باشد استفاده از کلاس پدر باعث خطای NullReference خواهد شد. و همچنین این کد Thread safe نمی باشد.الگوهای مرتبط با الگوی Singleton الگوهای Façade و Abstract Factory و بسیاری از الگوهای دیگر هستند که لازم است در برنامه از آنها فقط یک نمونه ساخته شده باشند که در زمان معرفی این الگوها توضیحات لازم ارایه خواهد شد.

الگوی Adapter چیست؟

همان گونه که از اسم این الگو مشخص است، هنگامی که دو کلاس واسط(Interface) های غیرمرتبط با یکدیگر داشته باشند این الگو واسط یکی را به دیگری تبدیل می کند که بتوانند با یکدیگر ارتباط برقرار کند.از این الگو که یک الگوی ساختاری است زمانی استفاده می شود که در یک برنامه بخواهیم که دو کلاس غیرمرتبط با یکدیگر کار کنند.

این الگو در برنامه هایی که از کلاس های آماده استفاده می شود و یا از کلاس هایی استفاده می شود که قبلا نوشته شده اند و به گونه ای باشد که طراحان نرم افزار اجازه تغییر در این کلاس ها را نداشته باشند. بسیاری از مثال های الگوی Adapter درگیر ورودی و خروجی هستند زیرا این دامنه ای است که همیشه تغییر می کند.

برای مثال برنامه هایی که در دهه 80 میلادی نوشته شده اند دارای UI بسیار ضعیف تری نسبت به برنامه های نوشته شده در هزاره سوم میلادی هستند. حال اگر دوباره نویسی همان برنامه های قبلی به صرفه نباشد و بخواهیم این برنامه ها با سخت افزارهای جدید همخوانی و سازگاری داشته باشند باید برنامه ای طراحی کنیم که بین این دو برنامه یعنی برنامه قدیمی و راه اندازهای سخت افزارهای جدید قرار بگیرد و بین این دو برنامه ارتباط برقرار کند.

به برنامه ای که بین این دو برنامه قرار می گیرد Adapter گویند. حال شاید به نظر برسد که استفاده از Adapter اصلاً نیاز نباشد و می توان واسط یکی از کلاس ها را تغییر داد تا بتواند کار کند، این کار زمانی ممکن است که بتوان به کد کلاس ها دسترسی داشت و تغییر کلاس ها باعث به وجود آمدن مشکل در برنامه نباشد و پیچیدگی برنامه را افزایش ندهد که در اکثر مواقع این عمل به صرفه نیست.ساختار این الگو به این شکل است:

ساختار الگوی Adapter

همانطور که در شکل دیده می شود کلاس Adapter از اینترفیس ITarget مشتق شده است و در یکی از متدهایی که در این کلاس وجود دارد (Request) متد مورد نظر را از کلاس Adaptee فراخوانی می کند. کلاس Adapter متدهای Adaptee را با متدها و خصوصیای Target وفق می دهد. به طور کلی اینترفیس ITarget همان اینترفیسی است که کاربر آن را پیاده سازی می کند و کلاس Adaptee همان کلاسی است که باید با برنامه وفق داده شود. کاربران برای استفاده فقط از کلاس Adapter نمونه سازی می کنند و نیازی به درگیری با ارتباط Target و Adaptee نخواهند بود.کد این الگو به شرح زیر است.

using System;

    public class Adaptee
    {
        public double SpecificRequest(double a, double b)
        {
            return a/b;
        }
    }

    public interface ITarget
    {
        string Request(int a);
    }

    public class Adapter : Adaptee, ITarget
    {
        public string Request(int a)
        {
            return "the result is" + (int) Math.Round(SpecificRequest(a, 5));
        }
    }

Adapter دوطرفه چیست؟

ساده ترین شکل الگوی Adapter شکل یک طرفه آن است که یک کلاس یا اینترفیس Target بوده و کلاس دیگر نقش Adaptee را داشت که تا این قسمت شرح داده شد. حال فرض کنید که می خواهیم هر دو طرف هم نقش Adaptee و هم نقش Target را داشته باشند. به گونه ای که از کلاس Adapter بتوان همه به شکلی استفاده کرد که متدهای هر دو طرف را داشته باشند.

در این صورت کلاس Adapter دارای متدها و خصوصیات هر دو کلاس می باشد. یک Adapter دو طرفه می تواند به جای هر دو کلاس Target و Adaptee مورد استفاده قرار بگیرد. برای این کار در زبانهایی مانند ++C که وراثت از چندین کلاس را پشتیبانی می کنند کار آسانی است. به این شکل که کلاس Adapter از دو کلاس دیگر ارث بری داشته باشد همانند ساختار زیر

با سلام به همه همراهان Itpro.ir در بخش های قبل در مباحثی کلی درباره ی شی گرایی و الگوهای طراحی مطرح شد و از این بخش به بعد به تک تک الگو ها می پردازیم و هرکدام را توضیح خواهیم داد. در این بخش به الگوهای *Singleton* و *Adapter* می پردازیم که نسبتا الگوهای ساده تری هستند می پردازیم.

!! الگوی Singleton
این الگو یکی از الگوهای سازنده (creational) است و در ساختن اشیا از کلاس ها کاربرد دارد. این الگو یکی از معروف ترین الگوهای مطرح شده توسط Gang of Four است.
*نکته: کلمه کاربر که در این سری مقالات استفاده می شود به کلاس هایی اطلاق می شود که از کلاس مورد بحث استفاده می کنند و منظور تنها کاربر انسانی نیست و ممکن است که یک زیرسیستم یا یک کلاس و یا حتی تابع main برنامه باشد.*

حالتی را در نظر بگیرید که کلاسی دارید که می خواهید در کل برنامه خود فقط یک شی از این کلاس ساخته شود و اجازه ساخته شدن نمونه جدید به استفاده کنندگان از این کلاس داده نشود. این عمل در مواقعی بسیار لازم و ضروری است. به طور مثال حالتی را درنظر بگیرید که در برنامه کلاسی وجود دارد که واسط تنظیمات برنامه است یعنی برنامه هنگام لود شدن تنظیمات خود را در آن بارگزاری می کند. حال اگر این شی یک شی در کل برنامه یکتا نباشد و هر بخش از برنامه که بخواهد تنظیمات را بخواند و یا تغییری در آن ایجاد کند مجبور باشد که یک شی جدید از کلاس تنظیمات بسازد مدیریت این اشیا مشکل می شود و همچنین باعث نابه سامانی در تنظیمات خواهد شد. راه حل این مسئله این است که از همان اول کلاس به گونه ای تعریف شود که اجازه ساختن نمونه جدید به کاربران ندهد و تنها کاربران بتوانند یک نمونه از کلاس به وجود آورند.
اگر به برخی از قسمت های سیستم عامل ویندوز هم نگاهی بکنیم متوجه می شویم که چنین مکانیزمی در آن تعبیه شده است مثلاً یک سیستم فایل برای مدیریت فایل ها وجود دارد و یا با وجود این که ممکن است چندین پرینتر به کامپیوتر متصل باشد ولی فقط یک printer spooler در سیستم وجود دارد.
برای به وجود آوردن چنین مکانیزمی شاید اولین راه حل این باشد که یک شی سراسری در کل برنامه تعریف شده و هروقت که برنامه ای بخواهد از این کلاس استفاده کند از شی سراسری تعریف شده استفاده کند. اما مشکلی که این راه حل دارد این است که این راه حل مانع ساخت شی جدید از کلاس نمی شود. یک راه حل بهتر این است که خود کلاس را مسئول این کار قرار دهیم که مواظب باشد که یک نمونه بیشتر نداشته باشد. این کار را الگوی Singleton انجام می دهد.

روش کار این الگو به این صورت است که یک نمونه از خود کلاس در داخل کلاس ساخته می شود و هر وقت که کلاس های دیگر خواستند از این کلاس استفاده کنند تنها می توانند به این نمونه ساخته شده دسترسی داشته باشند و نمی توانند از کلاس نمونه سازی کنند.
ساختار این الگو به این شکل است:
||ساختار الگوی Singleton::http://tosinso.com/files/get/18a1b123-cb56-48bd-87fd-496912caafd6||
همانطور که در شکل می بینید یک فیلد به نام instance داریم که از خود کلاس است و این فیلد تنها الگویی که قرار است ساخته شود را در خود نگهداری می کند. سازنده(constructor) این کلاس از نوع private بوده بنابراین نمی توان از این کلاس یک نمونه جدید توسط عملگر new ایجاد کرد. تنها راه ساختن یک نمونه از این کلاس فراخوانی متد GetInstance است.

!! ویژگی های این الگو
این الگو باعث می شود که دسترسی به نمونه های کلاس کنترل شود و تعداد خاص از نمونه ها ایجاد شود.
با استفاده از این الگو نیاز به ساختن متغیر های سراسری در فضای namespace کمتر شده و از اشغال فضای namespace توسط متغیرهای سراسری جلوگیری می کند.

کد پیاده سازی این الگو در زبان C# به شکل زیر است
<c#>
  public sealed class Singleton
    {
       private Singleton()
        {
        }
        private readonly static Singleton instance=new Singleton();
        public static Singleton UniqueInstance { get { return instance; } }
    }

<c#>
همانطور که درکد مشاهده می شود یک بار یک نمونه از کلاس ساخته می شود و تنها راه دسترسی به کلاس استفاده از ویژگی UniqueInstance  می باشد که نمونه ساخته شده را برمی گرداند. در این نوع پیاده سازی از همان ابتدا یک نمونه از کلاس ساخت شده است و استفاده می شود ولی می توان این نمونه را وقتی ساخت که درخواستی برای اولین باربه کلاس ارسال شود که به این شیوه *Lazy instantiate* گفته می شود. کد این روش به شکل زیر است.
<c#>
 public class LazySingleton
    {
        private LazySingleton(){}
        private static LazySingleton instance;

        public static LazySingleton UniqueInstance
        {
            get { return instance!=null?instance:new LazySingleton();}
        }

    }
<c#>
کدی که آورده شده است تا حدی می تواند هدف این الگو را که ساخته شدن یک نمونه از کلاس باشد را برآورده کند ولی اگر برنامه دارای چند thread باشد ممکن است در مواردی بیشتر از یک نمونه از کلاس ساخته شود که در اصطلاح گفته می شود برنامه *Thread Safe* نیست که به جای کد بالا از کد پایین استفاده می کنیم.
<c#>
    public class Singleton
    {
        private Singleton(){}

        class SingletonCreator
        {
            static SingletonCreator()
            {
            }
            internal static readonly Singleton UniqueInstance = new Singleton(); 
        }

        public static Singleton UniqueInstance
        {
            get { return SingletonCreator.UniqueInstance; }
        }
    }
<c#>
در کد بالا از یک کلاس داخلی برای ساخت نمونه از کلاس استفاده می شود که علاوه بر Thread safe بودن خاصیت Lazy instatiate هم دارد.
حال اگر نیاز باشد که از یک خانواده کلاس ها تنها یک نمونه ایجاد شود پیاده سازی این الگوی کمی متفاوت تر خواهد شد. برای مثال تصور کنید که یک کلاس میوه دارید که از آن کلاس های دیگری مانند سیب و پرتقال مشتق شده اند و لازم است که در برنامه فقط یک عدد میوه وجود داشته باشد یعنی اگر یک سیب وجود دارد دیگر نتوان میوه ی دیگری(چه سیب و چه پرتقال) ایجاد کرد. به منظور پیاده سازی چنین روشی به شکل زیر عمل می کنیم.
<c#>
 public  class SingleFruit
        {
            public string name;
            protected SingleFruit()
            { }
            protected static  SingleFruit Instance ;
            public static SingleFruit UniqueInstance
            {
                get { return Instance; }
            }
        }

        public class SingleApple : SingleFruit
        {
           
            private SingleApple()
            {
                name = Apple;
            }
            public static SingleFruit UniqueInstance
            {
                get { return Instance != null ? Instance :Instance= new SingleApple(); }
            }
        }

        public class SingleOrange : SingleFruit
        {
            private SingleOrange()
            {
                name = Orange;
            }
            public static SingleFruit UniqueInstance
            {
                get { return Instance != null ? Instance :Instance= new SingleOrange(); }
            }

        }
<c#>
با توجه به کد بالا اگر به کلاس های فرزندان مقداردهی نشده باشد استفاده از کلاس پدر باعث خطای NullReference خواهد شد. و همچنین این کد Thread safe نمی باشد.


الگوهای مرتبط با الگوی Singleton الگوهای Façade و Abstract Factory و بسیاری از الگوهای دیگر هستند که لازم است در برنامه از آنها فقط یک نمونه ساخته شده باشند که در زمان معرفی این الگوها توضیحات لازم ارایه خواهد شد.

!! الگوی Adapter
 همان گونه که از اسم این الگو مشخص است، هنگامی که دو کلاس واسط(Interface) های غیرمرتبط با یکدیگر داشته باشند این الگو واسط یکی را به دیگری تبدیل می کند که بتوانند با یکدیگر ارتباط برقرار کند.از این الگو که یک الگوی ساختاری است زمانی استفاده می شود که در یک برنامه بخواهیم که دو کلاس غیرمرتبط با یکدیگر کار کنند. این الگو در برنامه هایی که از کلاس های آماده استفاده می شود و یا از کلاس هایی استفاده می شود که قبلا نوشته شده اند و به گونه ای باشد که طراحان نرم افزار اجازه تغییر در این کلاس ها را نداشته باشند. بسیاری از مثال های الگوی Adapter درگیر ورودی و خروجی هستند زیرا این دامنه ای است که همیشه تغییر می کند.

برای مثال برنامه هایی که در دهه 80 میلادی نوشته شده اند دارای UI بسیار ضعیف تری نسبت به برنامه های نوشته شده در هزاره سوم میلادی هستند. حال اگر دوباره نویسی همان برنامه های قبلی به صرفه نباشد و بخواهیم این برنامه ها با سخت افزارهای جدید همخوانی و سازگاری داشته باشند باید برنامه ای طراحی کنیم که بین این دو برنامه یعنی برنامه قدیمی و راه اندازهای سخت افزارهای جدید قرار بگیرد و بین این دو برنامه ارتباط برقرار کند. به برنامه ای که بین این دو برنامه قرار می گیرد Adapter گویند. حال شاید به نظر برسد که استفاده از Adapter اصلاً نیاز نباشد و می توان واسط یکی از کلاس ها را تغییر داد تا بتواند کار کند، این کار زمانی ممکن است که بتوان به کد کلاس ها دسترسی داشت و تغییر کلاس ها باعث به وجود آمدن مشکل در برنامه نباشد و پیچیدگی برنامه را افزایش ندهد که در اکثر مواقع این عمل به صرفه نیست.
ساختار این الگو به این شکل است:
||ساختار الگوی Adapter::http://tosinso.com/files/get/087b6851-10b8-45e8-85d9-a26685d97c9b||
همانطور که در شکل دیده می شود کلاس Adapter از اینترفیس ITarget مشتق شده است و در یکی از متدهایی که در این کلاس وجود دارد (Request) متد مورد نظر را از کلاس Adaptee فراخوانی می کند. کلاس Adapter متدهای Adaptee را با متدها و خصوصیای Target وفق می دهد. به طور کلی اینترفیس ITarget  همان اینترفیسی است که کاربر آن را پیاده سازی می کند و کلاس Adaptee همان کلاسی است که باید با برنامه وفق داده شود. کاربران برای استفاده فقط از کلاس Adapter نمونه سازی می کنند و نیازی به درگیری با ارتباط Target و Adaptee نخواهند بود.
کد این الگو به شرح زیر است.
<c#>
using System;

    public class Adaptee
    {
        public double SpecificRequest(double a, double b)
        {
            return a/b;
        }
    }

    public interface ITarget
    {
        string Request(int a);
    }

    public class Adapter : Adaptee, ITarget
    {
        public string Request(int a)
        {
            return the result is + (int) Math.Round(SpecificRequest(a, 5));
        }
    }
<c#>

!!Adapter دوطرفه
ساده ترین شکل الگوی Adapter شکل یک طرفه آن است که یک کلاس یا اینترفیس Target بوده و کلاس دیگر نقش Adaptee را داشت که تا این قسمت شرح داده شد. حال فرض کنید که می خواهیم هر دو طرف هم نقش Adaptee و هم نقش Target را داشته باشند. به گونه ای که از کلاس Adapter بتوان همه به شکلی استفاده کرد که متدهای هر دو طرف را داشته باشند. در این صورت کلاس Adapter دارای متدها و خصوصیات هر دو کلاس می باشد. یک Adapter دو طرفه می تواند به جای هر دو کلاس Target و Adaptee مورد استفاده قرار بگیرد. برای این کار در زبانهایی مانند ++C که وراثت از چندین کلاس را پشتیبانی می کنند کار آسانی است. به این شکل که کلاس Adapter از دو کلاس دیگر ارث بری داشته باشد همانند ساختار زیر
||http://tosinso.com/files/get/1ee83c38-9f83-4eb4-adb4-588bc0be585b||
اما در بسیاری از زبان های برنامه نویسی رایج مانند #C و Java ارث بری از چندکلاس پشتیبانی نمی شود. بنابراین این راه حل در این زبان ها پاسخگو نیست. برای این که در این زبان ها از Adapter دو طرفه استفاده کنیم به شکل زیر عمل می کنیم.
<c#>
  public class Adaptee
    {
        public double SpecificRequest(double a, double b)
        {
            return a/b;
        }
    }

    public interface ITarget
    {
        string Request(int a);
    }

    public class Adapter : Adaptee, ITarget
    {
        public string Request(int a)
        {
            return the result is + (int) Math.Round(SpecificRequest(a, 5));
        }
    }

////////////////////////////////////////////////////////
internal class Program
    {
        private static void Main(string[] args)
        {
            ITarget aa = new Adapter();
            Console.WriteLine(aa.Request(5));
            Console.WriteLine((aa as Adaptee).SpecificRequest(8, 3));
         }

    }
<c#>
در کد بالا یکی از اینترفیس ها (IAircraft ) که همان Target است را در کلاس Adapter پیاده سازی می کنیم و از کلاس Adaptee ارث بری می نماییم. ساختار این عمل شبیه به همان استفاده از الگوی Adapter به شکل یک طرفه آن است ولی در استفاده به این شکل عمل می کنیم. همانطور که مشاهده می شود می توان از کلاس Adapter هم به عنوان یک نمونه از Target و هم به عنوان یک نمونه از Adaptee استفاده نمود. مشکلی که در زبان هایی مانند C# یا Java وجود دارد این است که باید Target را به عنوان اینترفیس معرفی کرده و در کلاس Adapter آن را پیاده سازی نمود ولی در زبانی مانند C++ چنین محدودیتی وجود ندارد.


نویسنده : مهدی عادلی
منبع : |جزیره برنامه نویسی وب سایت توسینسو::https://programming.tosinso.com|
هرگونه نشر و کپی برداری بدون ذکر منبع و نام نویسنده دارای اشکال اخلاقی می باشد.

اما در بسیاری از زبان های برنامه نویسی رایج مانند #C و Java ارث بری از چندکلاس پشتیبانی نمی شود. بنابراین این راه حل در این زبان ها پاسخگو نیست. برای این که در این زبان ها از Adapter دو طرفه استفاده کنیم به شکل زیر عمل می کنیم.

  public class Adaptee
    {
        public double SpecificRequest(double a, double b)
        {
            return a/b;
        }
    }

    public interface ITarget
    {
        string Request(int a);
    }

    public class Adapter : Adaptee, ITarget
    {
        public string Request(int a)
        {
            return "the result is" + (int) Math.Round(SpecificRequest(a, 5));
        }
    }

////////////////////////////////////////////////////////
internal class Program
    {
        private static void Main(string[] args)
        {
            ITarget aa = new Adapter();
            Console.WriteLine(aa.Request(5));
            Console.WriteLine((aa as Adaptee).SpecificRequest(8, 3));
         }

    }

در کد بالا یکی از اینترفیس ها (IAircraft ) که همان Target است را در کلاس Adapter پیاده سازی می کنیم و از کلاس Adaptee ارث بری می نماییم. ساختار این عمل شبیه به همان استفاده از الگوی Adapter به شکل یک طرفه آن است ولی در استفاده به این شکل عمل می کنیم. همانطور که مشاهده می شود می توان از کلاس Adapter هم به عنوان یک نمونه از Target و هم به عنوان یک نمونه از Adaptee استفاده نمود. مشکلی که در زبان هایی مانند C# یا Java وجود دارد این است که باید Target را به عنوان اینترفیس معرفی کرده و در کلاس Adapter آن را پیاده سازی نمود ولی در زبانی مانند C++ چنین محدودیتی وجود ندارد.

الگوی Observer

در این مقاله الگوی Observer معرفی خواهد شد و ساختار آن تشریح خواهد شد.

نقش الگوی Observer چیست؟

حالتی را تصور کنید که چند شی در برنامه وجود دارد که تغییر حالات یک شی دیگر را دنبال می کنند و با توجه به هر تغییر عملی را انجام می دهند. شاید اولین راه حلی که در این حالت، یافت شود این است که اشیا در یک حلقه شی مورد نظر را بررسی کنند تا اگر تغییری به وجود آمده بود با توجه به آن کاری انجام دهند. اما این بدترین راه حل است و باعث افت کارایی و همچنین طراحی بد برنامه خواهد شد. برای حل این مسئله الگوی Observer معرفی می شود.الگوی Observer یک ارتباط بین اشیا ایجاد می کند به طوری که وقتی یکی از اشیا تغییر حالت می دهد همه اشیا مرتبط با آن از این تغییر حالت اطلاع پیدا می کنند. معمولاَ در یک مجموعه از اشیا مرتبط این چنینی، یک منتشر کننده(publisher) و جود دارد و چندین شی وجود دارد که از تغییر حالت شی منتشر کننده آگاه می شوند.

تشریح الگوی Observer

در دنیای کامپیوتر امروزی از این الگو بسیار استفاده شده است. به عنوان مثال حالتی را تصور کنید که در یک سایت آمار فروش به صورت یک نمودار نمایش داده می شود. وقتی که یک عمل فروش انجام می شود این نمودار باید با توجه مقدار حجم فروش ها خود را بروزرسانی کند. حال شاید بتوان گفت که این کار را می توان بدون استفاده از الگویی پیاده سازی کرد ولی وقتی نیاز به الگوی Observer احساس می شود که در زمان اجرا بخواهیم مجموعه اشیائی را که تغییر شی منتشر کننده را دنبال می کنند را تغییر بدهیم

یعنی چند شی به این مجموعه اضافه کنیم و یا از آن کم کنیم. الگوی Observer یک الگوی رفتاری است.از استفاده های دیگری که از این الگو استفاده شده است مدیریت رویداد های یک برنامه است. به طور مثال وقتی در زبان #C در رویداد formLoad متدی را فرخوانی می کنیم وقتی که این رویداد در فرم رخ بدهد فرم همه ی توابع و اعمالی را که برای آن تعریف شده است را آگاه می کند که اجرا شوند.به طور کلی هرگاه بخواهیم با تغییر حالت یک شی، اشیا دیگر عمل خاصی را انجام دهند از این الگو استفاده می شود.

موارد استفاده الگوی Observer چیست؟

از این الگو در موارد زیر استفاده می شود:

وقتی که یک abstraction دارای دو جنبه باشد که یک به دیگری وابسته باشد و هر کدام از این جنبه ها در اشیا جداگانه باشند و بتوانند به طور مستقل عمل کنند و تغییرات مورد نیاز خود را روی اشیا خود اعمال کنند.

وقتی که با به وجود آمدن یک تغییر در یک شی لازم باشد که اشیا دیگر با توجه به تغییر به وجود آمده عمل خاصی انجام دهند و همچنین مشخص نیست که چندتا از اشیا باید عمل مورد نظر را انجام دهند.

وقتی که لازم باشد که یک شی بتواند به اشیا دیگر بدون توجه به ماهیت آن و یا شناختن آن اطلاع رسانی نماید.

ساختار الگوی Observer به چه شکل است؟

برای تشریح ساختار این الگو از عبارات زیر استفاده شده است:

  • Subject: شیئی است که اشیا تغییر حالات آن را دنبال می کنند.
  • Observer: شی یا اشیایی هستند که تغییر حالات Subject را دنبال می کنند.

ساختار این الگو به این صورت است که هر شی Observer که بخواهد از تغییر حالت شی Subject آگاه باشد باید خود را در لیست دنبال کنندگان Subject ثبت کند. برای این کار شی Observer متد Attach شی Subject را فراخوانی می کند و خود شی را به عنوان ورودی متد می فرستد و با این کار در ساختمان داده شی Subject ثبت می شود و هر گاه که رویدادی در Subject رخ دهد، این شی متد Notify خود را فراخوانی می کند که با این کار به همه Observerها اطلاع داده می شود.

اگر یک Observer نخواهد که دیگر رویدادها را دنبال کند متدل Detach مربوط به Subject را فراخوانی می کند و خود را به عنوان ورودی به آن می فرستد و با این کار از ساختمان داده ی Subjectحذف می شود و دیگر رویداد ها به آن اطلاع داده نخواهد شد. همه ی اشیای Observer اینترفیس IObserver را پیاده سازی می کنند. نمودار Class diagram این الگو به این شکل است.

نمودار class diagram  مربوط به الگوی Observer

کاربرد مدل های Push و Pull در چیست؟

برای ارتباط بین Subject و observer دو مکانیزم وجود دارد. مکانیزم اول که Push نام دارد به این شکل است که Subject وقتی می خواهد به observer اطلاع دهد تغییرات را با تمام جزئیات می فرستد و وقتی که observer این تغییرات را دریافت می کند همه ی اطلاعات را برای این که خود را update کند دارد و دیگر نیاز به اطلاعات بیشر از طرف subject نیست.

مکانیزم دوم که pull نام دارد این گونه عمل می کند که subject پیامی شبیه به آگهی به همه ی observer ها می فرستد و هر کدام از observer ها که بخواهد خود را آپدیت در خواست خود را به subject می فرستد تا اطلاعات مورد نیاز را بدست آورد.الگوی observer از هر دو مدل گفته شده پشتیبانی می کند.

از مزایای این الگو می توان موارد زیر را نام برد:

این الگو باعث کم کردن وابستگی observer و subject به یکدیگر می شود و در اصطلاح این دو موجودیت در برنامه tightly couple نخواهند بود و بنابراین می توان این دو موجودیت را در لایه های مختلف برنامه تعریف کرد و از این الگو استفاده نمود. این الگو از ارتباط broadcast پشتیبانی می کند.

بررسی برخی از مسائل پیاده سازی الگوی Observer

در ادامه به برخی از مسائلی که ممکن است در هنگام استفاده و پیاده سازی از این الگو پیش بیاید پرداخته می شود.

  • همانظور که گفته شد هر subject باید لیست هر کدام از observer ها را داشته باشد و برای این کار در پیاده سازی یک ارجاع به شی مورد نظر را ذخیره کند. به منظور ذخیره این ارجاع ها باید ساختمان داده ای در نظر گرفته شود که سرعت بالایی داشته باشد که در مواقعی که تعداد observer ها زیاد است باعث کندی برنامه نشود.
  • دنبال کردن بیش از یک subject توسط observer: برای این که یک observer بتواند بیش از یک subject را دنبال کند باید متد update خود را به گونه ای تعریف کند که با هر دوی subject ها سازگاری و همخوانی داشته باشد. برای subject راحت ترین کار این است که در فراخوانی متد update خود را به عنوان پارامتر به سمت observer بفرستد و خود observer تشخیص دهد که از طرف کدام یک از subject ها پیام را دریافت کرده است.
  • وقتی که عمل حذف یک subject انجام می شود، این عمل نباید باعث به وجود آمدن ارجاع های بی فایده (Dangling reference) شود. همچنین باید ساز و کاری اندیشیده شود که وقتی که یک observer حذف می شود نیز این مشکل پیش نیاید. برای حل این مشکل در طرف observer باید هنگامی که observer در حال از بین رفتن است خود را از لیست observer های یک subject حذف کند، به این شکل که در Destructor کلاس خود متد Detach مربوط به subject را فراخوانی نماید.
  • می توان رویدادهایی را که در subject به وجود می آیند را گروه بندی کرده و این قابلیت را به observer ها بدهیم که هنگام ثبت خود به عنوان observer مشخص کنند که قصد دنبال کردن کدام گروه را در subject دارند.
  • به علت پیچیدگی هایی که گفته شد ممکن است برای برقراری ارتباط بین observer و subject یک شی جدید به نام ChangeManager داشته باشیم که همه ی پیچیدگی های ارتباط را به این شی محول کنیم. که با این کار مدیریت مسائل گفته شده بسیار آسان تر خواهد بود. البته این کلاس ChangeManger می تواند یک نمونه از الگوی Mediaor باشد و به طور طبیعی باید تنها یک ChangeManager بین یک مجموعه observer و subject موجود باشد که برای این کار می توان از الگوی Singleton استفاده کرد.

الگوی Mediator در مقاله های بعدی شرح داده خواهد شد.

پیاده سازی الگوی Observer

پایه و اساس پیاده سازی این الگو به همان شکلی است که class diagram آن نشان داده شده است. بنابراین اگر بخواهیم این الگو را با زبانی مانند ++C پیاده سازی کنیم کد آن به شکل زیر خواهد شد.

class Subject;

class Observer
{
public:
	
	virtual ~Observer();
	virtual void Update(Subject *changedSubject) = 0;

private:
protected:
	Observer();

};
////////////////////////////////////////////////////////////////////////
class Subject
{
public:
	~Subject();
	void Attach(Observer*);
	void Detach(Observer*);
	int Number;
private:
void Notify();
	List<Observer*> *_observers;
};
void Subject::Attach(Observer *o)
{
	_observers->Append(o);
}
void Subject::Detach(Observer *o)
{
	_observers->Remove(o);
}
void Subject::Notify()
{
	ListIterator<Observer*> i(_observers);
	for (i.First(); !i.IsDone(); i.Next()) {
		i.CurrentItem()->Update(this);
	}
}


Subject::~Subject()
{
	ListIterator<Observer*> i(_observers);
	for (i.First(); !i.IsDone(); i.Next()) {
		Detach(i.CurrentItem());
	}
}
//////////////////////////////////////////////////////////////////
class ConcreteObserver:public Observer
{
public:
	ConcreteObserver(Subject* subject)
	{
		attachedSubject = subject;
		attachedSubject->Attach(this);
	}
	void Observer::Update(Subject *changedSubject)
	{
		cout << "changedSubject is:" << changedSubject->Number<<endl;
	}
	~ConcreteObserver()
	{
		attachedSubject->Detach(this);
	}
private:
	Subject* attachedSubject;

};
////////////////////////////////////////////////////////////////////////
void main()
{
	Subject* subject = new Subject;
	ConcreteObserver observer(subject);
}

در کد بالا کلاس Observer نقش همان اینترفیس را در class diagram آورده شده دارد. با توجه به کد بالا هر کلاسی که بخواهد خود را به عنوان observer مربوط به کلاس Subject قرار دهد باید از کلاس Observer ارث بری کند و متد Attach را از کلاس Subject فراخوانی کند(همانند Constructor مربوط به کلاس ConcreteObserver). با این کار خود را در لیست observers اضافه می کند و هر زمان که در کلاس Subject متد Notify فراخوانی شود متد Update این کلاس نیز فراخوانی خواهد شد.

هنگامی که خود کلاس observer از بین برود خود را از لیست observers حذف می کند و همچنین اگر کلاس Subject از بین برود همه کلاس های Observer حذف خواهند شد این عمل برای جلوگیری از به وجود آمدن dangling reference می باشد.ولی در زبان #C پیاده سازی این الگو به روش دیگری صورت می گیرد که بسیار راحت تر از کد آورده شده است. در زبان#C با استفاده از امکاناتی مانند event ها می توان این الگو را به راحتی پیاده سازی نمود. پیاده سازی این الگو در زبان #C به شرح زیر است:

 using System;
    using System.Collections;
    using System.Threading;

    public class ObserverPattern
    {
        private class Subject
        {
            public delegate void Callback(string s);
            public event Callback Notify;
            private readonly Simulator simulator = new Simulator();
            private const int speed = 200;
            public string SubjectState { get; set; }

            public void Go()
            {
                new Thread(Run).Start();
            }

            private void Run()
            {
                foreach (string s in simulator)
                {
                    Console.WriteLine("Subject: " + s);
                    SubjectState = s;
                    Notify(s);
                    Thread.Sleep(speed); // milliseconds
                }
            }

            private interface IObserver
            {
                void Update(string state);
            }

            private class Observer : IObserver
            {
                private readonly string name;
                private Subject subject;
                private string state;
                private readonly string gap;

                public Observer(Subject subject, string name, string gap)
                {
                    this.subject = subject;
                    this.name = name;
                    this.gap = gap;
                    subject.Notify += Update;
                }

                public void Update(string subjectState)
                {
                    state = subjectState;
                    Console.WriteLine(gap + name + ": " + state);
                }
            }

            private static void Main()
            {
                var subject = new Subject();
                var Observer = new Observer(subject, "Center", "\t\t");
                var observer2 = new Observer(subject, "Right", "\t\t\t\t");
                subject.Go();
            }

            private class Simulator : IEnumerable
            {
                private readonly string[] moves = {"5", "3", "1", "6", "7"};

                public IEnumerator GetEnumerator()
                {
                    foreach (var element in moves)
                        yield return element;
                }
            }
        }
    }

همانطور که در این کد مشاهده می شود در کلاس Subject یک event به نام Notify تعریف شده است که یک رشته به عنوان ورودی می گیرد. هر کلاس Observer که بخواهد تغییرات Subject را دنبال کند باید متد Update خود را به شکل زیر به Notify معرفی کند:

  subject.Notify += Update;

و اگر کلاسی بخواهد که دیگر تغییرات را دنبال نکند در خط بالا به جای علامت += از علامت -= استفاده می کند. در قطعه کد بالا که از برنامه نویسی چند نخی (Thread) استفاده شده است یک thread مسئول اجرای عمل Notify می باشد که با اجرا شدن این عمل متد Update کلاس های Observer فراخوانی می شوند. همانطور که مشاهده می شود برخلاف زبان C++ نیازی به تعریف لیست و اضافه و حذف کردن و در کل درگیری مستقیم با لیست Observer ها نخواهیم داشت.لازم به ذکر است که در تعریف کلاس Simulator از الگوی iterator استفاده شده است که این الگو در مقاله های بعدی شرح داده خواهد شد.از الگوهای مرتبط با این الگو می توان Singleton, Mediator, State, Memento را نام برد.

الگوی Iterator

در ادامه سری مقالات الگوی های طراحی نرم افزار های شی گرا به الگوی iterator خواهیم پرداخت.

نقش الگوی Iterator چیست؟

این الگو راهی برای دست یافتن به عناصر موجود در یک مجموعه را فراهم می کند. این دست یابی بدون توجه به ساختار مجموعه به صورت ترتیبی است. همچنین این الگو می تواند عناصر را به شکل های گوناگونی فیلتر نماید.

تشریح الگوی Iterator

برای ذخیره داده های مرتبط در زبان های برنامه نویسی از مجموعه عناصر استفاده می شود. این مجموعه عناصر می توانند مجموعه ها ، لیست ها و آرایه ها و... باشند. هر کدام از این مجموعه ها با توجه به شرایط استفاده می تواند بسیار مفید باشد. هر کدام از این مجموعه ها عناصر خود را به گونه ای متفاوت ذخیره می کنند. حال تصور کنید که در برنامه خود از آرایه استفاده می کرده اید

و بنابر تغییرات برنامه و نیاز به وجود آمده ناگزیر به استفاده از لیست باشید باید همه ی قسمت های برنامه که از آرایه مذکور استفاده می کرده اند را تغییر داده و بازنویسی کنید که این بار از لیست به جای آرایه استفاده کنند. خود این عمل بسیار مشکل است و می تواند باعث به وجود آمدن ناسازگاری های بسیاری شود. راه حل این است که روش استفاده از مجموعه عناصر به شکل یکتا پیاده سازی شود.

الگوی iterator یکی از ساده ترین الگوها و در عین حال یکی از الگوهای پرکاربرد در بین الگوهای طراحی می باشد. این الگو یک واسط استاندارد برای استفاده کنندگان فراهم می کند که بدون توجه به چگونگی پیاده سازی یک مجموعه از عناصر، استفاده کنندگان بتوانند به اعضای مجموعه دسترسی داشته باشند. بسیاری از زبان های برنامه نویسی شی گرا مانند #C و Java در مجموعه های خود از این الگو استفاده کرده اند.

در استفاده از این الگو باید دو مفهوم iterator و enumerator را تعریف کنیم. مفاهیم iterator و enumerator دارای قدمت طولانی می باشد. Enumerator مسئول یافتن شی بعدی است که شرط خاصی را دارد. به طور مثال اگر بخواهیم عدد اول کوچکتر از هزار بعدی را پیدا کنیم از enumerator استفاده می کنیم و این مجموعه اعداد 1 تا 1000 را مجموعه enumerable می نامیم. مفهوم iterator به این معنی است که توسط حلقه ای یک مجموعه از اشیا را از اول تا آخر پیمایش نماییم. الگوی iterator باید هر دوی این مفاهیم را پیاده سازی کند.

موارد استفاده الگوی Iterator

از این الگو در موارد زیر استفاده می شود:

  • برای دسترسی به محتوای یک شئ تجمعی بدون در نظر گرفتن ساختار داخلی آن.
  • برای پیمایش در اشیا تجمعی(هر گاه هر شی خود دارای زیر گروه هایی از اشیا باشد و بخواهیم به همه آن ها دسترسی داشته باشیم.)
  • برای فراهم کردن یک واسط یکتا برای پیمایش ساختار های تنوعی متفاوت.

ساختار الگوی Iterator

ساختار این الگو در زبان C# اینگونه پیاده سازی شده است که برای پیاده سازی iterator از حلقه foreach استفاده می شود و برای هر مجموعه ای که بخواهد از این الگو استفاده کند باید اینترفیس Ienumerable را پیاده سازی کند. ساختار این الگو به این شکل است:

ساختار الگوی Iterator

همانطور که در شکل دیده می شود مجموعه ها اینترفیس IEnumerable را پیاده سازی می کنند. این اینترفیس دارای یک تابع به نام GetEnumerator() می باشد که همان کار enumerator را پیاده سازی می کند. اگر این اینترفیس و این تابع در مجموعه ای پیاده سازی نشده باشد قسمت iterator یعنی حلقه foreach نمی تواند کار خود را انجام دهد. در زبان هایی که این مکانیزم در آن پیاده سازی نشده است مانند++C باید از ساختار زیر استفاده کرد:

ساختار الگوی iterator در زبان هایی که این الگو را داخل خود ندارند

در این نمودار برنامه برای پیمایش یک لیست در این ساختار از ListIterator استفاده می شود که در طول یک حلقه به کاوش لیست می پردازد.

پیاده سازی الگوی Iterator

اول پیاده سازی این الگو برای زبان ++C را توضیح می دهم که هیچگونه اینترفیس آماده ای ندارد و کاربر باید از اول خود به پیاده سازی این الگو بپردازد و سپس به پیاده سازی این الگو در زبان #C خواهیم پرداخت.برای پیمایش یک مجموعه از عناصر باید توابع داخل کلاس Iterator را بازنویسی نماییم. یعنی کلاس ConcreteIteratorاین توابع را با توجه به یک مجموعه خاص پیاده سازی می کند. قطعه کد زیر این مثال را برای یک لیست نشان می دهد.

template <class Item>
class Iterator {
public:
	virtual void First() = 0;
	virtual void Next() = 0;
	virtual bool IsDone() const = 0;
	virtual Item CurrentItem() const = 0;
protected:
	Iterator();
};


template <class Item>
class ListIterator : public Iterator<Item> {
public:
	ListIterator(const List<Item>* aList);
	virtual void First(){
		_current = 0;
	}
	virtual void Next(){
		_current++;
	}
	virtual bool IsDone() const{
		return _current >= _list->Count();
	}
	virtual Item CurrentItem() const{
		if (IsDone()) {
			throw IteratorOutOfBounds;
		}
		return _list->Get(_current);
	}
private:
	const List<Item>* _list;
	long _current;
};

void PrintNumbers(ListIterator<int> i) {
	for (i.First(); !i.IsDone(); i.Next()) {
		cout<<i.CurrentItem()<<endl;
	}
}

همانگونه که در کد نشان داده شده است کلاسی به نام Iterator وجود دارد که فقط چند تابع virtual دارد و این توابع توسط کلاس ListIterator که از کلاس قبلی ارث بری کرده است پیاده سازی شده اند. در تابع PrintNumbers نحوه استفاده از این الگو را می توان دید که از اولین عنصر آن پیمایش شروع شده و تا آخرین عنصر پیش می رود و هرکدام از عناصر را در یک خط چاپ می نماید.در زبان های سطح بالا تر مانند Java و #C اینترفیس هایی وجود دارند که کار را آسان تر کرده و نیازی نیست که از ابتدا شروع به نوشتن این الگو نماییم.قطعه کد زیر پیاده سازی این الگو را برای ماه های سال در زبان#C نشان می دهد.

    using System;
    using System.Collections;

    public class Iterator
    {
        public class MonthCollection:IEnumerable
        {
            string[] months = { "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" };
            public IEnumerator GetEnumerator()
            {
                foreach (var month in months)
                {
                    yield return month;
                }
            }
        }

        static void main()
        {
            var collection = new MonthCollection();
            foreach (var element in collection)
            {
                Console.WriteLine(element);
            }
        }
    }

همان طور که در کد بالا دیده می شود مجموعه ای که قصد پیاده سازی این الگو در آن را داریم یک آرایه رشته ای است که ماه ها را در خود ذخیره کرده است. توسط کلمه کلیدی yield می توان به کامپایلر فهماند که مقداری که return می کنیم مقدار enumerator است یعنی عنصر بعدی است. البته می توان در داخل foreach موجود در تابع getenumerator شرط گذاشت که همه ماه ها را به خروجی نفرستد. با این کار هرکدام از عناصر که شرط مورد نظر را داشته باشند به foreach موجود در تابع main ارسال می شود.

الگوی Command

این الگو به این شکل است که بین کاربری که یک درخواست را ارسال کرده و شیئی که می تواند آن دستور را اجرا کند یک فاصله می اندازد. این الگو یک الگوی چندکاره است که امکانات زیر را پشتیبانی می کند.

  • ارسال در خواست ها برای گیرنده های مختلف
  • توانایی صف بندی و لاگ گرفتن از درخواست های دریافت شده و یا رد کردن در خواست ها
  • ایجاد تراکنش هاس سطح بالا از اعمال سطح پایین
  • انجام اعمال Redo و Undo

شرح الگوی Command

لگوی Command در سیستم منو های بسیاری از برنامه های معروف استفاده می شود. در بسیاری از نرم افزار هایی که امروزه با آنها سرو کار داریم منویی به نام Edit دارند که اعمال کپی و کات کردن را داخل منوی Edit دارند و از طرفی هم همان اعمال کپی و کات کردن در داخل نوار ابزار بالای صفحه نیز موجود می باشد. این به این معنی است که هر دوی آنها یک عمل را انجام می دهند. و این اعمال دارای قابلیت Undo نیز می باشند. همه ی این اعمال کاربرد های الگوی Command می باشد.

طراحی الگوی Command


ساختار الگوی Command

طراحی الگوی command به شکل زیر است. کلاس Client روش معینی دارد که درخواست خود را اعلام کند. Receiver ها که ممکن است بیش از یکی باشند می دانند که چگونه باید درخواست کاربر را اجرا نمایند با توجه به مثال منو ها که قبلا گفتیم یک فرمان Cut برای یک متن در قسمتی از برنامه اجرا می شود و فرمان Cut مربوط به یک عکس در قسمت دیگری از برنامه هندل می شود.کلاس Command به عنوان یک واسط (interface)بین Client و Receiver عمل می نماید. در یک شی Command درخواست های Client مشخص شده است و همچنین اعمال مربوط به این درخواست ها و گیرنده آن نیز در کلاس Command معین گردیده است.

ممکن است که Client بخواهد وضعیت خود را نیز برای دریافت کننده ارسال کند که کلاس Command این اجازه را می دهد. کلاس Invoker برای جدا کردن کلاس client از کلاس Receiver می باشد. به بیان ساده تصور کنید که Client تابع Execute مربوط به Invoker را فراخوانی می کند. با این کار درخواست کاربر به Command ارسال می شود و تابع Action مربوط به Receiver مورد نظر اجرا می شود. یک برنامه می تواند دارای تعداد زیادی درخواست با انواع متفاوت باشد که هر کدام به گیرنده های مربوط به خود ارسال می شوند. اینترفیس ICommand اطمینان حاصل می کند که هرکدام از درخواست ها به فرم استاندارد برای گیرنده مورد نظر باشد.

کلاس هایی که در این الگو نقش دارند عبارتند از:

  • Client: کلاس های Command را می سازد و اجرا می کند.
  • ICommand: اینترفیسی است که عملیات قابل اجرا را مشخص می نماید.
  • Invoker: درخواست اجرای Action را به کلاس Command می دهد.
  • Command: کلاسی که عملیات اجرایی را پیاده سازی می کند که در داخل این عملیات دستورات فراخوانی دستوراالعمل های روی گیرنده وجود دارد.

از ویژگی های الگوی Command می توان به موارد زیر اشاره کرد:

  • دستورات در کلاس Command می توانند با هم ترکیب شده و دستورات بزرگتری به وجود آورند.
  • دستورات جدید می توانند به مجموعه ما اضافه شوند بدون این که خللی در کار دستورات قبلی به وجود آورند.

پیاده سازی الگوی Command

یک مثال ساده از پیاده سازی این الگو در ادامه آمده است.

 using System;

    internal class Program
    {
        private delegate void Invoker();

        private static Invoker Execute, Undo, Redo;

        private class Command
        {
            public Command(Receiver receiver)
            {
                Execute = receiver.Action;
                Redo = receiver.Action;
                Undo = receiver.Reverse;
            }
        }

        public class Receiver
        {
            private string build, oldBuild;
            private readonly string s = "Itpro string  ";

            public void Action()
            {
                oldBuild = build;
                build += s;
                Console.WriteLine("Receiver is adding " + build);
            }

            public void Reverse()
            {
                build = oldBuild;
                Console.WriteLine("Receiver is reversing to " + build);
            }
        }

        private static void Main(string[] args)
        {
            new Command(new Receiver());
            Execute();
            Redo();
            Undo();
            Execute();
            Console.ReadKey();
        }

    }
مثالی از استفاده از الگوی Command

کلاس Invoker وICommand به عنوان یک نوع delegate معرفی شده اند و در خط بعد سه شی از آن ساخته شده است. نام هرکدام از اشیا با توجه به کاری که کاربر از آنها می خواهد نام گذاری شده اند. دستور مربوط به کلاس Command در داخل Receiver با استفاده از دو تابع Action و Reverse پیاده سازی شده است. دستورات Execute و Redo هر دو تابع Action را اجرا می نمایند و دستور Undo تابع Reverse را اجرا می کند. در این کد Receiver مسئول نگهداری حالت شی است و همانگونه که در کد می بینید هر بار که اجرا می شود مقدار s تغییر می کند. همچنین در این کد عمل undo کردن فقط برای یک بار ممکن است ولی اگر بخواهیم این کار را در واقعیت انجام دهیم باید برای نگهداری حالت های قبلی باید بیشتر از یک عمل را در نظر بگیریم که مکانیزم های متفاوتی برای پیاده سازی آن وجود دارد.

Command های دارای چند گیرنده (Multireceiver)

حال اگر در یک برنامه چندین نوع delegate داشته باشیم و بیشتر از یک گیرنده داشته باشیم چه اتفاقی خواهد افتاد؟ اول از همه باید نام delegate ها (Invoker) باید با هم متفاوت باشد. اشیاء Command باید به گونه ای باشند که بین اشیا delegate و گیرنده ها ارتباط ایجاد کند. در برنامه ای که در ادامه آورده شده است، دو کلاس Command و دو گیرنده وجود دارند. چون هر دوی command ها از delegateها (invoker) یکسان استفاده می کنند، Client دستورات را اول در یکی از گیرنده ها و سپس در دیگری اجرا می کند ولی ممکن است این کار لازم نباشد. برای این که این مشکل را حل کنیم می توانیم اشیا delegaet بیشتری معرفی کنیم یا آنها را در داخل Command ها گروه بندی نماییم که در مثال زیر نشان داده شده است.

public class MultiReceiver
    {
        private delegate void Invoker();

        private delegate void InvokerSet(string s);

        private static Invoker Execute, Redo, Undo;
        private static InvokerSet Set;

        class Command
        {
            public Command(Receiver receiver)
            {
                Set = delegate
                {
                    Console.WriteLine("Not implemented- default of Itpro used");
                    receiver.S = "Itpro";
                };
                Execute = receiver.Action;
                Redo = receiver.Action;
                Undo = receiver.Reverse;
            }
        }

        class Command2
        {
            public Command2(Receiver2 receiver2)
            {
                Set = receiver2.SetData;
                Execute = receiver2.DoIt;
                Redo = receiver2.DoIt;
                Undo = () => Console.WriteLine("Not Implemented");
            }
        }
         class Receiver
         {
             private string build, oldBuild;
             private string s = "Itpro String ";

            public string S { get { return s; } set { s = value; } }


            public void Action()
            {
                oldBuild = build;
                build += s;
                Console.WriteLine("Receiver is adding "+build);
            }

            public void Reverse()
            {
                build = oldBuild;
                Console.WriteLine("Receiver is reverting to "+build);
            }
        }

        class Receiver2
        {
            private string build, oldBuild;
            private string s = "Itpro String2 ";

            public void SetData(string s)
            {
                this.s = s;
            }

            public void DoIt()
            {
                oldBuild = build;
                build += s;
                Console.WriteLine("Receiver is building "+build);
            }
        }

        class Client
        {
            public void ClientMain()
            {
                new Command(new Receiver());
                Execute();
                Redo();
                Undo();
                Set("III");
                Execute();
                Console.WriteLine();
                new Command2(new Receiver2());
                Set("Hoses ");
                Execute();
                Set("Castles ");
                Undo();
                Execute();
                Redo();
            }
        }

        private static void Main(string[] args)
        {
            new Client().ClientMain();
        }
    }

از کاربرد های دیگر این الگو ثبت لاگ برنامه است که یک تاریخچه از کارهایی که انجام شده است نگهداری می کند مثلا ساده ترین نوع لاگ گیری این است که تعداد انجام یک کار را بشماریم. برای این کار عملیات مورد نظر را در قسمت Invoker پیاده سازی می کنیم.

الگوی Mediator

در ادامه با بحث الگوهای طراحی به شرح الگوی Meditor خواهیم پرداخت

با سلام خدمت همه دوستان توسینسویی ، در ادامه با بحث الگوهای طراحی به شرح الگوی Meditor خواهیم پرداخت

||http://tosinso.com/files/get/7a7d07ba-8430-425c-bdd1-f745d5c4078d||

!!مقدمه
همان طور که در بخش اول این سری مقالات اشاره کردیم یکی از اصولی که در طراحی نرم افزار باید رعایت شود این است که در طراحی نرم افزار ها کلاس ها و اشیائی که طراحی می شوند باید حداقل وابستگی را به یکدیگر داشته باشند. به این معنی که هرکدام به شکل جداگانه کار خود را انجام بدهند و در صورت نیاز فارغ از این که هرکدام چگونه وظیفه خود را انجام می دهند با یکدیگر تعامل داشته باشند. این تعامل باید به گونه ای باشد که وقتی تغییری در یکی از کلاس ها اعمال شد کلاسی که با کلاس تغییر داده شده همکاری می کند نیازمند تغییر نباشد. به این اصل در طراحی نرم افزار loosly coupling گفته می شود. یکی از الگو های طراحی که در رعایت اصل گفته شده بسیار تاثیر گذار است الگوی mediator می باشد. این الگو شیئی را تعریف می کند که این شیء ارتباط بین مجموعه ای از اشیا دیگر را برقرار می کند و نوع این ارتباط را کپسوله سازی می کند. به این معنی که این الگو زمینه ای برای ارتباط بین اشیا به وجود می آورد به گونه ای که اشیا از ماهیت یکدیگر اطلاعی ندارند و همان طور که از نام این الگو می توان فهمید این الگو یک میانجی بین سایر اشیا دیگر است. این الگو همچنین می تواند پروتکل هایی را قرار دهد که سایر اشیا از آن ها پیروی کنند.
||http://tosinso.com/files/get/3c1931da-29b1-4e1e-81ec-2bc30a79da74||

!!شرح
در طراحی نرم افزار های شی گرا ترجیح بر این است که اعمال و رفتار ها بین اشیا توزیع و تقسیم شوند.  خرد کردن سیستم به بخش های متفاوت باعث می شود که قابلیت استفاده مجدد (reusablity) سیسم افزایش پیدا کند. مشکلی که در انجام این کار به وجود می آید این است که این بخش های مختلف سیستم نیازمند ارتباط با یکدیگر می باشند که اگر این ارتباطات کنترل نشوند خود همین مکانیزم ارتباطی پیچیدگی بسیاری برای سیستم به وجود می آورد که قابلیت reusablity و نگهداری و تغییر سیستم را پایین می آورد. وظیفه این الگو ارتباط است. این ارتباط ها می توانند متفاوت باشند. مثلا می توان بین دو شی ارتباط برقرار کرد و یا بین گروهی از اشیا ارتباط برقرار کرد. اغلب پروتکلی وجود دارد که همه ی اعضای گروه از آن پیروی می کنند. الگوی mediator با استفاده از این پروتکل ارتباط بین اشیا را برقرار می کند. 

برای این که اهمیت این الگو مشخص شود، یک شبکه کامپیوتری را در نظر بگیرید که در آن کامپیوتر های با یکدیگر ارتباط دارند و هرکدام از کامپیوتر ها می توانند به راحتی می توانند با دیگری ارتباط داشته باشند. اگر پیاده سازی شما به این گونه باشد که این کامپیوتر ها را دو به دو به یکدیگر متصل کنید باید بگویم که یک پیاده سازی فاجعه انجام داده اید. زیرا این روش هم هزینه پیاده سازی زیادی دارد و هم پیچیده است و هم خطایابی آن سخت است. به جای این کار در شبکه های امروزی از یک سوییچ استفاده می شود که همه کامپیوتر ها به آن متصل شده و از طریق آن با یکدیگر تعامل دارند. در برنامه های چت نیز چنین مکانیزمی پیاده سازی شده است. 

اگر بخواهیم الگوی Mediator را با این مکانیزم مقایسه کنیم این الگو همان سوییچ را پیاده سازی می نماید. حال یک مثال نرم افزاری شرح می دهیم. یک لیست ایمیل را در نظر بگیرید که در آن ایمیل های اعضای سایت Itpro ثبت شده است. وقتی که مطلب جدیدی در سایت گذاشته می شود به همه ی اعضای این لیست برای آگاهی یک ایمیل ارسال خواهد شد. در این صورت سرویسی که این لیست ایمیل را در اختیار دارد و ایمیل ها را ارسال می کند از الگوی Mediator استفاده می کند. حال اگر کاربری این قصد را داشته باشد که فقط مطالب قسمت انجمن نرم افزار سایت را دنبال کند و با بقیه مطالب کاری نداشته باشد به این سرویس می گوید که این کار را برای آن انجام دهد. حالت دیگر این است که یک کاربر نمی خواهد هیچ ایمیلی درباره ی مطالب سایت به او ارسال شود و این کار را با همان سرویس میانجی انجام می دهد.


!! طراحی الگوی Mediator
حال به شرح UML الگوی Mediator می پردازیم. همانگونه که در شکل دیده می شود این الگو فقط از دو کلاس تشکیل شده است که با ارسال پیام با یکدیگر ارتباط برقرار می کنند. این کلاس ها عبارتند از:
*Colleage*  یک mediator را ثبت می کند که با استفاده از آن mediator با بقیه اشیا ارتباط برقرار می نماید. ارسال اطلاعات توسط send انجام می شود. این کلاس حتما یک متد Receive دارد که اطلاعات ارسالی بقیه اشیا را توسط آن دریافت می کند.
*Mediator* با استفاده از دلیگیت Respond پیام رسیده را به کلاس های Colleage ارسال می کند.
||http://tosinso.com/files/get/f833e59c-636f-42ea-8406-7a1bccc1474d||

!! پیاده سازی
نکته هایی که در پیاده سازی این الگو وجود دارد این است که هر شی از کلاس Colleage هنگام ساخته شدن یک شی mediator می گیرند و آن را به صورت private نگهداری می کنند. و نکته دیگر این که هر شی از کلاس Mediator یک لیست از اشیا Colleage نگهداری می کند و آن را به صورت private نگهداری می نماید. برای ارسال به همه اشیا Colleage ثبت شده در یک mediator ما باید نام آنها به همراه تابع Respond آنها را در اختیار داشته باشیم که این کار را می توانیم توسط یک دیکشنری انجام دهیم. ولی راه ساده تر از این کار در زبان C# استفاده از دلیگیت ها است. کد زیر کار کردن این متد را نمایش می دهد.
<c#>
using System;
using System.Collections.Generic;

namespace MediatorPattern
{
    public class Mediator
    {
        public delegate void Callback(string message, string from);

        private Callback respond;

        public void SignOn(Callback method)
        {
            respond += method;
        }

        public void Block(Callback method)
        {
            respond -= method;
        }

        public void Unblock(Callback method)
        {
            respond += method;
        }

        public void Send(string message, string from)
        {
            respond(message, from);
            Console.WriteLine();
        }
    }

    public class Colleague
    {
        private Mediator mediator;
        protected string name;

        public Colleague(Mediator mediator, string name)
        {
            this.mediator = mediator;
            mediator.SignOn(Receive);
            this.name = name;
        }

        public virtual void Receive(string message, string from)
        {
            Console.WriteLine(name +  received from  + from + :  + message);
        }

        public void Send(string message)
        {
            Console.WriteLine(Send (From  + name + ):  + message);
            mediator.Send(message, name);
        }
    }

    public class ColleagueB : Colleague
    {
        public ColleagueB(Mediator mediator, string name)
            : base(mediator, name)
        {
        }

        public override void Receive(string message, string from)
        {
            if (!String.Equals(from, name))
                Console.WriteLine(name +  received from  + from + :  + message);
        }
    }

    static void Main()
{
    Mediator m = new Mediator( );
    Colleague head1 = new Colleague(m,John);
    ColleagueB branch1 = new ColleagueB(m,David);
    Colleague head2 = new Colleague(m,Lucy);
    head1.Send(Meeting on Tuesday, please all ack);
    branch1.Send(Ack);
    m.Block(branch1.Receive);
    head1.Send(Still awaiting some Acks);
    head2.Send(Ack);
    m.Unblock(branch1.Receive);
    head1.Send(Thanks all);
}


}
<c#>
خروجی کد بالا به شکل زیر خواهد بود.
<text>
Send (From John): Meeting on Tuesday, please all ack
John received from John: Meeting on Tuesday, please all ack
David received from John: Meeting on Tuesday, please all ack
Lucy received from John: Meeting on Tuesday, please all ack

Send (From David): Ack
John received from David: Ack
Lucy received from David: Ack

Send (From John): Still awaiting some Acks
John received from John: Still awaiting some Acks
Lucy received from John: Still awaiting some Acks

Send (From Lucy): Ack
John received from Lucy: Ack
Lucy received from Lucy: Ack

Send (From John): Thanks all
John received from John: Thanks all
Lucy received from John: Thanks all
David received from John: Thanks all

<text>
در کد بالا وقتی که می خواهیم یک شی از کلاس colleage بسازیم یک شی mediator به همراه نام خود شی به آن اختصاص می دهیم. وقتی هم که می خواهیم یک شی را برای mediator معرفی کنیم تابع send آن شی را به تابع SignOn مربوط به mediator میفرستیم. از دیگر اعمالی که کد بالا انجام می دهد این است که این شی امکان بلاک کردن برخی اشیا را دارد که البته مکانیزم آن بسیار ساده است.یک برنامه چت داینامیک تر و پویاتر از برنامه ارسال ایمیل است. زیرا پیامی که ارسال می شود به سرعت توسط دیگر کاربران دریافت می شود و مانند مثال قبل نیست که فقط یک ایمیل ارسال شود.

!!استفاده از الگوی Mediator
الگوی Mediator در بسیاری از سیستم های مدرن که از پروتکل Send/receive استفاده می کنند مانند list serverها و چت روم ها استفاده شده است. الگوی mediator علاوه بر ارتباطات انسانی نقش بسیار مهمی در متمرکز کردن ارتباطات بین اشیا دارد. اگر اشیا به طور مستقیم با یکدیگر ارتباط داشته باشند درک ارتباطات آنها بسیار مشکل خواهد بود. پیاده سازی این الگو می تواند نقش بسیار مهمی در کارایی سیستم داشته باشد. زیرا که هرچقدر ارتباطات بین اشیا سریع تر انجام بشود کارایی بالا می رود و گاهی اوقات ممکن است که یک گلوگاه شود. این الگو همچنین در امنیت سیستم ها نیز تاثیر بسیاری دارد. از مزایا و معایب این الگو می توان به موارد زیر اشاره کرد. مزایا:

	• اشای همکار (Colleage) را از هم جدا می کند و وابستگی بین آنها را از بین می برد
	• اشیا می توانند به راحتی وظایف خود را انجام دهند و بدون داشتن اطلاعات دقیق از اشیا دیگر با آنها ارتباط داشته باشند.
	• کنترل ارتباطات با استفاده از این الگو متمرکز می شود.
	• ارتباطات اشیا با یکدیگر به آسانی قابل فهم و استفاده مجدد خواهد بود.
*معایب*
	• پیچیدگی کلاس mediator ممکن است بالا باشد.
	• در صورت پیاده سازی نادرست ممکن است که فهم کلاس mediator سخت باشد.
الگوی Mediator یک الگوی رفتاری می باشد. *Itpro* باشید.

نویسنده : مهدی عادلی
منبع : |جزیره برنامه نویسی وب سایت توسینسو::https://programming.tosinso.com|
هرگونه نشر و کپی برداری بدون ذکر منبع و نام نویسنده دارای اشکال اخلاقی می باشد.

همان طور که در بخش اول این سری مقالات اشاره کردیم یکی از اصولی که در طراحی نرم افزار باید رعایت شود این است که در طراحی نرم افزار ها کلاس ها و اشیائی که طراحی می شوند باید حداقل وابستگی را به یکدیگر داشته باشند. به این معنی که هرکدام به شکل جداگانه کار خود را انجام بدهند و در صورت نیاز فارغ از این که هرکدام چگونه وظیفه خود را انجام می دهند با یکدیگر تعامل داشته باشند.

این تعامل باید به گونه ای باشد که وقتی تغییری در یکی از کلاس ها اعمال شد کلاسی که با کلاس تغییر داده شده همکاری می کند نیازمند تغییر نباشد. به این اصل در طراحی نرم افزار loosly coupling گفته می شود. یکی از الگو های طراحی که در رعایت اصل گفته شده بسیار تاثیر گذار است الگوی mediator می باشد.

این الگو شیئی را تعریف می کند که این شیء ارتباط بین مجموعه ای از اشیا دیگر را برقرار می کند و نوع این ارتباط را کپسوله سازی می کند. به این معنی که این الگو زمینه ای برای ارتباط بین اشیا به وجود می آورد به گونه ای که اشیا از ماهیت یکدیگر اطلاعی ندارند و همان طور که از نام این الگو می توان فهمید این الگو یک میانجی بین سایر اشیا دیگر است. این الگو همچنین می تواند پروتکل هایی را قرار دهد که سایر اشیا از آن ها پیروی کنند.

با سلام خدمت همه دوستان توسینسویی ، در ادامه با بحث الگوهای طراحی به شرح الگوی Meditor خواهیم پرداخت

||http://tosinso.com/files/get/7a7d07ba-8430-425c-bdd1-f745d5c4078d||

!!مقدمه
همان طور که در بخش اول این سری مقالات اشاره کردیم یکی از اصولی که در طراحی نرم افزار باید رعایت شود این است که در طراحی نرم افزار ها کلاس ها و اشیائی که طراحی می شوند باید حداقل وابستگی را به یکدیگر داشته باشند. به این معنی که هرکدام به شکل جداگانه کار خود را انجام بدهند و در صورت نیاز فارغ از این که هرکدام چگونه وظیفه خود را انجام می دهند با یکدیگر تعامل داشته باشند. این تعامل باید به گونه ای باشد که وقتی تغییری در یکی از کلاس ها اعمال شد کلاسی که با کلاس تغییر داده شده همکاری می کند نیازمند تغییر نباشد. به این اصل در طراحی نرم افزار loosly coupling گفته می شود. یکی از الگو های طراحی که در رعایت اصل گفته شده بسیار تاثیر گذار است الگوی mediator می باشد. این الگو شیئی را تعریف می کند که این شیء ارتباط بین مجموعه ای از اشیا دیگر را برقرار می کند و نوع این ارتباط را کپسوله سازی می کند. به این معنی که این الگو زمینه ای برای ارتباط بین اشیا به وجود می آورد به گونه ای که اشیا از ماهیت یکدیگر اطلاعی ندارند و همان طور که از نام این الگو می توان فهمید این الگو یک میانجی بین سایر اشیا دیگر است. این الگو همچنین می تواند پروتکل هایی را قرار دهد که سایر اشیا از آن ها پیروی کنند.
||http://tosinso.com/files/get/3c1931da-29b1-4e1e-81ec-2bc30a79da74||

!!شرح
در طراحی نرم افزار های شی گرا ترجیح بر این است که اعمال و رفتار ها بین اشیا توزیع و تقسیم شوند.  خرد کردن سیستم به بخش های متفاوت باعث می شود که قابلیت استفاده مجدد (reusablity) سیسم افزایش پیدا کند. مشکلی که در انجام این کار به وجود می آید این است که این بخش های مختلف سیستم نیازمند ارتباط با یکدیگر می باشند که اگر این ارتباطات کنترل نشوند خود همین مکانیزم ارتباطی پیچیدگی بسیاری برای سیستم به وجود می آورد که قابلیت reusablity و نگهداری و تغییر سیستم را پایین می آورد. وظیفه این الگو ارتباط است. این ارتباط ها می توانند متفاوت باشند. مثلا می توان بین دو شی ارتباط برقرار کرد و یا بین گروهی از اشیا ارتباط برقرار کرد. اغلب پروتکلی وجود دارد که همه ی اعضای گروه از آن پیروی می کنند. الگوی mediator با استفاده از این پروتکل ارتباط بین اشیا را برقرار می کند. 

برای این که اهمیت این الگو مشخص شود، یک شبکه کامپیوتری را در نظر بگیرید که در آن کامپیوتر های با یکدیگر ارتباط دارند و هرکدام از کامپیوتر ها می توانند به راحتی می توانند با دیگری ارتباط داشته باشند. اگر پیاده سازی شما به این گونه باشد که این کامپیوتر ها را دو به دو به یکدیگر متصل کنید باید بگویم که یک پیاده سازی فاجعه انجام داده اید. زیرا این روش هم هزینه پیاده سازی زیادی دارد و هم پیچیده است و هم خطایابی آن سخت است. به جای این کار در شبکه های امروزی از یک سوییچ استفاده می شود که همه کامپیوتر ها به آن متصل شده و از طریق آن با یکدیگر تعامل دارند. در برنامه های چت نیز چنین مکانیزمی پیاده سازی شده است. 

اگر بخواهیم الگوی Mediator را با این مکانیزم مقایسه کنیم این الگو همان سوییچ را پیاده سازی می نماید. حال یک مثال نرم افزاری شرح می دهیم. یک لیست ایمیل را در نظر بگیرید که در آن ایمیل های اعضای سایت Itpro ثبت شده است. وقتی که مطلب جدیدی در سایت گذاشته می شود به همه ی اعضای این لیست برای آگاهی یک ایمیل ارسال خواهد شد. در این صورت سرویسی که این لیست ایمیل را در اختیار دارد و ایمیل ها را ارسال می کند از الگوی Mediator استفاده می کند. حال اگر کاربری این قصد را داشته باشد که فقط مطالب قسمت انجمن نرم افزار سایت را دنبال کند و با بقیه مطالب کاری نداشته باشد به این سرویس می گوید که این کار را برای آن انجام دهد. حالت دیگر این است که یک کاربر نمی خواهد هیچ ایمیلی درباره ی مطالب سایت به او ارسال شود و این کار را با همان سرویس میانجی انجام می دهد.


!! طراحی الگوی Mediator
حال به شرح UML الگوی Mediator می پردازیم. همانگونه که در شکل دیده می شود این الگو فقط از دو کلاس تشکیل شده است که با ارسال پیام با یکدیگر ارتباط برقرار می کنند. این کلاس ها عبارتند از:
*Colleage*  یک mediator را ثبت می کند که با استفاده از آن mediator با بقیه اشیا ارتباط برقرار می نماید. ارسال اطلاعات توسط send انجام می شود. این کلاس حتما یک متد Receive دارد که اطلاعات ارسالی بقیه اشیا را توسط آن دریافت می کند.
*Mediator* با استفاده از دلیگیت Respond پیام رسیده را به کلاس های Colleage ارسال می کند.
||http://tosinso.com/files/get/f833e59c-636f-42ea-8406-7a1bccc1474d||

!! پیاده سازی
نکته هایی که در پیاده سازی این الگو وجود دارد این است که هر شی از کلاس Colleage هنگام ساخته شدن یک شی mediator می گیرند و آن را به صورت private نگهداری می کنند. و نکته دیگر این که هر شی از کلاس Mediator یک لیست از اشیا Colleage نگهداری می کند و آن را به صورت private نگهداری می نماید. برای ارسال به همه اشیا Colleage ثبت شده در یک mediator ما باید نام آنها به همراه تابع Respond آنها را در اختیار داشته باشیم که این کار را می توانیم توسط یک دیکشنری انجام دهیم. ولی راه ساده تر از این کار در زبان C# استفاده از دلیگیت ها است. کد زیر کار کردن این متد را نمایش می دهد.
<c#>
using System;
using System.Collections.Generic;

namespace MediatorPattern
{
    public class Mediator
    {
        public delegate void Callback(string message, string from);

        private Callback respond;

        public void SignOn(Callback method)
        {
            respond += method;
        }

        public void Block(Callback method)
        {
            respond -= method;
        }

        public void Unblock(Callback method)
        {
            respond += method;
        }

        public void Send(string message, string from)
        {
            respond(message, from);
            Console.WriteLine();
        }
    }

    public class Colleague
    {
        private Mediator mediator;
        protected string name;

        public Colleague(Mediator mediator, string name)
        {
            this.mediator = mediator;
            mediator.SignOn(Receive);
            this.name = name;
        }

        public virtual void Receive(string message, string from)
        {
            Console.WriteLine(name +  received from  + from + :  + message);
        }

        public void Send(string message)
        {
            Console.WriteLine(Send (From  + name + ):  + message);
            mediator.Send(message, name);
        }
    }

    public class ColleagueB : Colleague
    {
        public ColleagueB(Mediator mediator, string name)
            : base(mediator, name)
        {
        }

        public override void Receive(string message, string from)
        {
            if (!String.Equals(from, name))
                Console.WriteLine(name +  received from  + from + :  + message);
        }
    }

    static void Main()
{
    Mediator m = new Mediator( );
    Colleague head1 = new Colleague(m,John);
    ColleagueB branch1 = new ColleagueB(m,David);
    Colleague head2 = new Colleague(m,Lucy);
    head1.Send(Meeting on Tuesday, please all ack);
    branch1.Send(Ack);
    m.Block(branch1.Receive);
    head1.Send(Still awaiting some Acks);
    head2.Send(Ack);
    m.Unblock(branch1.Receive);
    head1.Send(Thanks all);
}


}
<c#>
خروجی کد بالا به شکل زیر خواهد بود.
<text>
Send (From John): Meeting on Tuesday, please all ack
John received from John: Meeting on Tuesday, please all ack
David received from John: Meeting on Tuesday, please all ack
Lucy received from John: Meeting on Tuesday, please all ack

Send (From David): Ack
John received from David: Ack
Lucy received from David: Ack

Send (From John): Still awaiting some Acks
John received from John: Still awaiting some Acks
Lucy received from John: Still awaiting some Acks

Send (From Lucy): Ack
John received from Lucy: Ack
Lucy received from Lucy: Ack

Send (From John): Thanks all
John received from John: Thanks all
Lucy received from John: Thanks all
David received from John: Thanks all

<text>
در کد بالا وقتی که می خواهیم یک شی از کلاس colleage بسازیم یک شی mediator به همراه نام خود شی به آن اختصاص می دهیم. وقتی هم که می خواهیم یک شی را برای mediator معرفی کنیم تابع send آن شی را به تابع SignOn مربوط به mediator میفرستیم. از دیگر اعمالی که کد بالا انجام می دهد این است که این شی امکان بلاک کردن برخی اشیا را دارد که البته مکانیزم آن بسیار ساده است.یک برنامه چت داینامیک تر و پویاتر از برنامه ارسال ایمیل است. زیرا پیامی که ارسال می شود به سرعت توسط دیگر کاربران دریافت می شود و مانند مثال قبل نیست که فقط یک ایمیل ارسال شود.

!!استفاده از الگوی Mediator
الگوی Mediator در بسیاری از سیستم های مدرن که از پروتکل Send/receive استفاده می کنند مانند list serverها و چت روم ها استفاده شده است. الگوی mediator علاوه بر ارتباطات انسانی نقش بسیار مهمی در متمرکز کردن ارتباطات بین اشیا دارد. اگر اشیا به طور مستقیم با یکدیگر ارتباط داشته باشند درک ارتباطات آنها بسیار مشکل خواهد بود. پیاده سازی این الگو می تواند نقش بسیار مهمی در کارایی سیستم داشته باشد. زیرا که هرچقدر ارتباطات بین اشیا سریع تر انجام بشود کارایی بالا می رود و گاهی اوقات ممکن است که یک گلوگاه شود. این الگو همچنین در امنیت سیستم ها نیز تاثیر بسیاری دارد. از مزایا و معایب این الگو می توان به موارد زیر اشاره کرد. مزایا:

	• اشای همکار (Colleage) را از هم جدا می کند و وابستگی بین آنها را از بین می برد
	• اشیا می توانند به راحتی وظایف خود را انجام دهند و بدون داشتن اطلاعات دقیق از اشیا دیگر با آنها ارتباط داشته باشند.
	• کنترل ارتباطات با استفاده از این الگو متمرکز می شود.
	• ارتباطات اشیا با یکدیگر به آسانی قابل فهم و استفاده مجدد خواهد بود.
*معایب*
	• پیچیدگی کلاس mediator ممکن است بالا باشد.
	• در صورت پیاده سازی نادرست ممکن است که فهم کلاس mediator سخت باشد.
الگوی Mediator یک الگوی رفتاری می باشد. *Itpro* باشید.

نویسنده : مهدی عادلی
منبع : |جزیره برنامه نویسی وب سایت توسینسو::https://programming.tosinso.com|
هرگونه نشر و کپی برداری بدون ذکر منبع و نام نویسنده دارای اشکال اخلاقی می باشد.

شرح الگوی Mediator

در طراحی نرم افزار های شی گرا ترجیح بر این است که اعمال و رفتار ها بین اشیا توزیع و تقسیم شوند. خرد کردن سیستم به بخش های متفاوت باعث می شود که قابلیت استفاده مجدد (reusablity) سیسم افزایش پیدا کند. مشکلی که در انجام این کار به وجود می آید این است که این بخش های مختلف سیستم نیازمند ارتباط با یکدیگر می باشند که اگر این ارتباطات کنترل نشوند خود همین مکانیزم ارتباطی پیچیدگی بسیاری برای سیستم به وجود می آورد که قابلیت reusablity و نگهداری و تغییر سیستم را پایین می آورد.

وظیفه این الگو ارتباط است. این ارتباط ها می توانند متفاوت باشند. مثلا می توان بین دو شی ارتباط برقرار کرد و یا بین گروهی از اشیا ارتباط برقرار کرد. اغلب پروتکلی وجود دارد که همه ی اعضای گروه از آن پیروی می کنند. الگوی mediator با استفاده از این پروتکل ارتباط بین اشیا را برقرار می کند.

برای این که اهمیت این الگو مشخص شود، یک شبکه کامپیوتری را در نظر بگیرید که در آن کامپیوتر های با یکدیگر ارتباط دارند و هرکدام از کامپیوتر ها می توانند به راحتی می توانند با دیگری ارتباط داشته باشند. اگر پیاده سازی شما به این گونه باشد که این کامپیوتر ها را دو به دو به یکدیگر متصل کنید باید بگویم که یک پیاده سازی فاجعه انجام داده اید.

زیرا این روش هم هزینه پیاده سازی زیادی دارد و هم پیچیده است و هم خطایابی آن سخت است. به جای این کار در شبکه های امروزی از یک سوییچ استفاده می شود که همه کامپیوتر ها به آن متصل شده و از طریق آن با یکدیگر تعامل دارند. در برنامه های چت نیز چنین مکانیزمی پیاده سازی شده است.

اگر بخواهیم الگوی Mediator را با این مکانیزم مقایسه کنیم این الگو همان سوییچ را پیاده سازی می نماید. حال یک مثال نرم افزاری شرح می دهیم. یک لیست ایمیل را در نظر بگیرید که در آن ایمیل های اعضای سایت Itpro ثبت شده است. وقتی که مطلب جدیدی در سایت گذاشته می شود به همه ی اعضای این لیست برای آگاهی یک ایمیل ارسال خواهد شد.

در این صورت سرویسی که این لیست ایمیل را در اختیار دارد و ایمیل ها را ارسال می کند از الگوی Mediator استفاده می کند. حال اگر کاربری این قصد را داشته باشد که فقط مطالب قسمت انجمن نرم افزار سایت را دنبال کند و با بقیه مطالب کاری نداشته باشد به این سرویس می گوید که این کار را برای آن انجام دهد. حالت دیگر این است که یک کاربر نمی خواهد هیچ ایمیلی درباره ی مطالب سایت به او ارسال شود و این کار را با همان سرویس میانجی انجام می دهد.

طراحی الگوی Mediator

حال به شرح UML الگوی Mediator می پردازیم. همانگونه که در شکل دیده می شود این الگو فقط از دو کلاس تشکیل شده است که با ارسال پیام با یکدیگر ارتباط برقرار می کنند. این کلاس ها عبارتند از:

  • Colleage یک mediator را ثبت می کند که با استفاده از آن mediator با بقیه اشیا ارتباط برقرار می نماید. ارسال اطلاعات توسط send انجام می شود. این کلاس حتما یک متد Receive دارد که اطلاعات ارسالی بقیه اشیا را توسط آن دریافت می کند.
  • Mediator با استفاده از دلیگیت Respond پیام رسیده را به کلاس های Colleage ارسال می کند.
با سلام خدمت همه دوستان توسینسویی ، در ادامه با بحث الگوهای طراحی به شرح الگوی Meditor خواهیم پرداخت

||http://tosinso.com/files/get/7a7d07ba-8430-425c-bdd1-f745d5c4078d||

!!مقدمه
همان طور که در بخش اول این سری مقالات اشاره کردیم یکی از اصولی که در طراحی نرم افزار باید رعایت شود این است که در طراحی نرم افزار ها کلاس ها و اشیائی که طراحی می شوند باید حداقل وابستگی را به یکدیگر داشته باشند. به این معنی که هرکدام به شکل جداگانه کار خود را انجام بدهند و در صورت نیاز فارغ از این که هرکدام چگونه وظیفه خود را انجام می دهند با یکدیگر تعامل داشته باشند. این تعامل باید به گونه ای باشد که وقتی تغییری در یکی از کلاس ها اعمال شد کلاسی که با کلاس تغییر داده شده همکاری می کند نیازمند تغییر نباشد. به این اصل در طراحی نرم افزار loosly coupling گفته می شود. یکی از الگو های طراحی که در رعایت اصل گفته شده بسیار تاثیر گذار است الگوی mediator می باشد. این الگو شیئی را تعریف می کند که این شیء ارتباط بین مجموعه ای از اشیا دیگر را برقرار می کند و نوع این ارتباط را کپسوله سازی می کند. به این معنی که این الگو زمینه ای برای ارتباط بین اشیا به وجود می آورد به گونه ای که اشیا از ماهیت یکدیگر اطلاعی ندارند و همان طور که از نام این الگو می توان فهمید این الگو یک میانجی بین سایر اشیا دیگر است. این الگو همچنین می تواند پروتکل هایی را قرار دهد که سایر اشیا از آن ها پیروی کنند.
||http://tosinso.com/files/get/3c1931da-29b1-4e1e-81ec-2bc30a79da74||

!!شرح
در طراحی نرم افزار های شی گرا ترجیح بر این است که اعمال و رفتار ها بین اشیا توزیع و تقسیم شوند.  خرد کردن سیستم به بخش های متفاوت باعث می شود که قابلیت استفاده مجدد (reusablity) سیسم افزایش پیدا کند. مشکلی که در انجام این کار به وجود می آید این است که این بخش های مختلف سیستم نیازمند ارتباط با یکدیگر می باشند که اگر این ارتباطات کنترل نشوند خود همین مکانیزم ارتباطی پیچیدگی بسیاری برای سیستم به وجود می آورد که قابلیت reusablity و نگهداری و تغییر سیستم را پایین می آورد. وظیفه این الگو ارتباط است. این ارتباط ها می توانند متفاوت باشند. مثلا می توان بین دو شی ارتباط برقرار کرد و یا بین گروهی از اشیا ارتباط برقرار کرد. اغلب پروتکلی وجود دارد که همه ی اعضای گروه از آن پیروی می کنند. الگوی mediator با استفاده از این پروتکل ارتباط بین اشیا را برقرار می کند. 

برای این که اهمیت این الگو مشخص شود، یک شبکه کامپیوتری را در نظر بگیرید که در آن کامپیوتر های با یکدیگر ارتباط دارند و هرکدام از کامپیوتر ها می توانند به راحتی می توانند با دیگری ارتباط داشته باشند. اگر پیاده سازی شما به این گونه باشد که این کامپیوتر ها را دو به دو به یکدیگر متصل کنید باید بگویم که یک پیاده سازی فاجعه انجام داده اید. زیرا این روش هم هزینه پیاده سازی زیادی دارد و هم پیچیده است و هم خطایابی آن سخت است. به جای این کار در شبکه های امروزی از یک سوییچ استفاده می شود که همه کامپیوتر ها به آن متصل شده و از طریق آن با یکدیگر تعامل دارند. در برنامه های چت نیز چنین مکانیزمی پیاده سازی شده است. 

اگر بخواهیم الگوی Mediator را با این مکانیزم مقایسه کنیم این الگو همان سوییچ را پیاده سازی می نماید. حال یک مثال نرم افزاری شرح می دهیم. یک لیست ایمیل را در نظر بگیرید که در آن ایمیل های اعضای سایت Itpro ثبت شده است. وقتی که مطلب جدیدی در سایت گذاشته می شود به همه ی اعضای این لیست برای آگاهی یک ایمیل ارسال خواهد شد. در این صورت سرویسی که این لیست ایمیل را در اختیار دارد و ایمیل ها را ارسال می کند از الگوی Mediator استفاده می کند. حال اگر کاربری این قصد را داشته باشد که فقط مطالب قسمت انجمن نرم افزار سایت را دنبال کند و با بقیه مطالب کاری نداشته باشد به این سرویس می گوید که این کار را برای آن انجام دهد. حالت دیگر این است که یک کاربر نمی خواهد هیچ ایمیلی درباره ی مطالب سایت به او ارسال شود و این کار را با همان سرویس میانجی انجام می دهد.


!! طراحی الگوی Mediator
حال به شرح UML الگوی Mediator می پردازیم. همانگونه که در شکل دیده می شود این الگو فقط از دو کلاس تشکیل شده است که با ارسال پیام با یکدیگر ارتباط برقرار می کنند. این کلاس ها عبارتند از:
*Colleage*  یک mediator را ثبت می کند که با استفاده از آن mediator با بقیه اشیا ارتباط برقرار می نماید. ارسال اطلاعات توسط send انجام می شود. این کلاس حتما یک متد Receive دارد که اطلاعات ارسالی بقیه اشیا را توسط آن دریافت می کند.
*Mediator* با استفاده از دلیگیت Respond پیام رسیده را به کلاس های Colleage ارسال می کند.
||http://tosinso.com/files/get/f833e59c-636f-42ea-8406-7a1bccc1474d||

!! پیاده سازی
نکته هایی که در پیاده سازی این الگو وجود دارد این است که هر شی از کلاس Colleage هنگام ساخته شدن یک شی mediator می گیرند و آن را به صورت private نگهداری می کنند. و نکته دیگر این که هر شی از کلاس Mediator یک لیست از اشیا Colleage نگهداری می کند و آن را به صورت private نگهداری می نماید. برای ارسال به همه اشیا Colleage ثبت شده در یک mediator ما باید نام آنها به همراه تابع Respond آنها را در اختیار داشته باشیم که این کار را می توانیم توسط یک دیکشنری انجام دهیم. ولی راه ساده تر از این کار در زبان C# استفاده از دلیگیت ها است. کد زیر کار کردن این متد را نمایش می دهد.
<c#>
using System;
using System.Collections.Generic;

namespace MediatorPattern
{
    public class Mediator
    {
        public delegate void Callback(string message, string from);

        private Callback respond;

        public void SignOn(Callback method)
        {
            respond += method;
        }

        public void Block(Callback method)
        {
            respond -= method;
        }

        public void Unblock(Callback method)
        {
            respond += method;
        }

        public void Send(string message, string from)
        {
            respond(message, from);
            Console.WriteLine();
        }
    }

    public class Colleague
    {
        private Mediator mediator;
        protected string name;

        public Colleague(Mediator mediator, string name)
        {
            this.mediator = mediator;
            mediator.SignOn(Receive);
            this.name = name;
        }

        public virtual void Receive(string message, string from)
        {
            Console.WriteLine(name +  received from  + from + :  + message);
        }

        public void Send(string message)
        {
            Console.WriteLine(Send (From  + name + ):  + message);
            mediator.Send(message, name);
        }
    }

    public class ColleagueB : Colleague
    {
        public ColleagueB(Mediator mediator, string name)
            : base(mediator, name)
        {
        }

        public override void Receive(string message, string from)
        {
            if (!String.Equals(from, name))
                Console.WriteLine(name +  received from  + from + :  + message);
        }
    }

    static void Main()
{
    Mediator m = new Mediator( );
    Colleague head1 = new Colleague(m,John);
    ColleagueB branch1 = new ColleagueB(m,David);
    Colleague head2 = new Colleague(m,Lucy);
    head1.Send(Meeting on Tuesday, please all ack);
    branch1.Send(Ack);
    m.Block(branch1.Receive);
    head1.Send(Still awaiting some Acks);
    head2.Send(Ack);
    m.Unblock(branch1.Receive);
    head1.Send(Thanks all);
}


}
<c#>
خروجی کد بالا به شکل زیر خواهد بود.
<text>
Send (From John): Meeting on Tuesday, please all ack
John received from John: Meeting on Tuesday, please all ack
David received from John: Meeting on Tuesday, please all ack
Lucy received from John: Meeting on Tuesday, please all ack

Send (From David): Ack
John received from David: Ack
Lucy received from David: Ack

Send (From John): Still awaiting some Acks
John received from John: Still awaiting some Acks
Lucy received from John: Still awaiting some Acks

Send (From Lucy): Ack
John received from Lucy: Ack
Lucy received from Lucy: Ack

Send (From John): Thanks all
John received from John: Thanks all
Lucy received from John: Thanks all
David received from John: Thanks all

<text>
در کد بالا وقتی که می خواهیم یک شی از کلاس colleage بسازیم یک شی mediator به همراه نام خود شی به آن اختصاص می دهیم. وقتی هم که می خواهیم یک شی را برای mediator معرفی کنیم تابع send آن شی را به تابع SignOn مربوط به mediator میفرستیم. از دیگر اعمالی که کد بالا انجام می دهد این است که این شی امکان بلاک کردن برخی اشیا را دارد که البته مکانیزم آن بسیار ساده است.یک برنامه چت داینامیک تر و پویاتر از برنامه ارسال ایمیل است. زیرا پیامی که ارسال می شود به سرعت توسط دیگر کاربران دریافت می شود و مانند مثال قبل نیست که فقط یک ایمیل ارسال شود.

!!استفاده از الگوی Mediator
الگوی Mediator در بسیاری از سیستم های مدرن که از پروتکل Send/receive استفاده می کنند مانند list serverها و چت روم ها استفاده شده است. الگوی mediator علاوه بر ارتباطات انسانی نقش بسیار مهمی در متمرکز کردن ارتباطات بین اشیا دارد. اگر اشیا به طور مستقیم با یکدیگر ارتباط داشته باشند درک ارتباطات آنها بسیار مشکل خواهد بود. پیاده سازی این الگو می تواند نقش بسیار مهمی در کارایی سیستم داشته باشد. زیرا که هرچقدر ارتباطات بین اشیا سریع تر انجام بشود کارایی بالا می رود و گاهی اوقات ممکن است که یک گلوگاه شود. این الگو همچنین در امنیت سیستم ها نیز تاثیر بسیاری دارد. از مزایا و معایب این الگو می توان به موارد زیر اشاره کرد. مزایا:

	• اشای همکار (Colleage) را از هم جدا می کند و وابستگی بین آنها را از بین می برد
	• اشیا می توانند به راحتی وظایف خود را انجام دهند و بدون داشتن اطلاعات دقیق از اشیا دیگر با آنها ارتباط داشته باشند.
	• کنترل ارتباطات با استفاده از این الگو متمرکز می شود.
	• ارتباطات اشیا با یکدیگر به آسانی قابل فهم و استفاده مجدد خواهد بود.
*معایب*
	• پیچیدگی کلاس mediator ممکن است بالا باشد.
	• در صورت پیاده سازی نادرست ممکن است که فهم کلاس mediator سخت باشد.
الگوی Mediator یک الگوی رفتاری می باشد. *Itpro* باشید.

نویسنده : مهدی عادلی
منبع : |جزیره برنامه نویسی وب سایت توسینسو::https://programming.tosinso.com|
هرگونه نشر و کپی برداری بدون ذکر منبع و نام نویسنده دارای اشکال اخلاقی می باشد.

پیاده سازی الگوی Mediator

نکته هایی که در پیاده سازی این الگو وجود دارد این است که هر شی از کلاس Colleage هنگام ساخته شدن یک شی mediator می گیرند و آن را به صورت private نگهداری می کنند. و نکته دیگر این که هر شی از کلاس Mediator یک لیست از اشیا Colleage نگهداری می کند و آن را به صورت private نگهداری می نماید. برای ارسال به همه اشیا Colleage ثبت شده در یک mediator ما باید نام آنها به همراه تابع Respond آنها را در اختیار داشته باشیم که این کار را می توانیم توسط یک دیکشنری انجام دهیم. ولی راه ساده تر از این کار در زبان C# استفاده از دلیگیت ها است. کد زیر کار کردن این متد را نمایش می دهد.

using System;
using System.Collections.Generic;

namespace MediatorPattern
{
    public class Mediator
    {
        public delegate void Callback(string message, string from);

        private Callback respond;

        public void SignOn(Callback method)
        {
            respond += method;
        }

        public void Block(Callback method)
        {
            respond -= method;
        }

        public void Unblock(Callback method)
        {
            respond += method;
        }

        public void Send(string message, string from)
        {
            respond(message, from);
            Console.WriteLine();
        }
    }

    public class Colleague
    {
        private Mediator mediator;
        protected string name;

        public Colleague(Mediator mediator, string name)
        {
            this.mediator = mediator;
            mediator.SignOn(Receive);
            this.name = name;
        }

        public virtual void Receive(string message, string from)
        {
            Console.WriteLine(name + " received from " + from + ": " + message);
        }

        public void Send(string message)
        {
            Console.WriteLine("Send (From " + name + "): " + message);
            mediator.Send(message, name);
        }
    }

    public class ColleagueB : Colleague
    {
        public ColleagueB(Mediator mediator, string name)
            : base(mediator, name)
        {
        }

        public override void Receive(string message, string from)
        {
            if (!String.Equals(from, name))
                Console.WriteLine(name + " received from " + from + ": " + message);
        }
    }

    static void Main()
{
    Mediator m = new Mediator( );
    Colleague head1 = new Colleague(m,"John");
    ColleagueB branch1 = new ColleagueB(m,"David");
    Colleague head2 = new Colleague(m,"Lucy");
    head1.Send("Meeting on Tuesday, please all ack");
    branch1.Send("Ack");
    m.Block(branch1.Receive);
    head1.Send("Still awaiting some Acks");
    head2.Send("Ack");
    m.Unblock(branch1.Receive);
    head1.Send("Thanks all");
}


}

خروجی کد بالا به شکل زیر خواهد بود.

Send (From John): Meeting on Tuesday, please all ack
John received from John: Meeting on Tuesday, please all ack
David received from John: Meeting on Tuesday, please all ack
Lucy received from John: Meeting on Tuesday, please all ack

Send (From David): Ack
John received from David: Ack
Lucy received from David: Ack

Send (From John): Still awaiting some Acks
John received from John: Still awaiting some Acks
Lucy received from John: Still awaiting some Acks

Send (From Lucy): Ack
John received from Lucy: Ack
Lucy received from Lucy: Ack

Send (From John): Thanks all
John received from John: Thanks all
Lucy received from John: Thanks all
David received from John: Thanks all

در کد بالا وقتی که می خواهیم یک شی از کلاس colleage بسازیم یک شی mediator به همراه نام خود شی به آن اختصاص می دهیم. وقتی هم که می خواهیم یک شی را برای mediator معرفی کنیم تابع send آن شی را به تابع SignOn مربوط به mediator میفرستیم. از دیگر اعمالی که کد بالا انجام می دهد این است که این شی امکان بلاک کردن برخی اشیا را دارد که البته مکانیزم آن بسیار ساده است.یک برنامه چت داینامیک تر و پویاتر از برنامه ارسال ایمیل است. زیرا پیامی که ارسال می شود به سرعت توسط دیگر کاربران دریافت می شود و مانند مثال قبل نیست که فقط یک ایمیل ارسال شود.

استفاده از الگوی Mediator

الگوی Mediator در بسیاری از سیستم های مدرن که از پروتکل Send/receive استفاده می کنند مانند list serverها و چت روم ها استفاده شده است. الگوی mediator علاوه بر ارتباطات انسانی نقش بسیار مهمی در متمرکز کردن ارتباطات بین اشیا دارد. اگر اشیا به طور مستقیم با یکدیگر ارتباط داشته باشند درک ارتباطات آنها بسیار مشکل خواهد بود. پیاده سازی این الگو می تواند نقش بسیار مهمی در کارایی سیستم داشته باشد. زیرا که هرچقدر ارتباطات بین اشیا سریع تر انجام بشود کارایی بالا می رود و گاهی اوقات ممکن است که یک گلوگاه شود. این الگو همچنین در امنیت سیستم ها نیز تاثیر بسیاری دارد. از مزایا و معایب این الگو می توان به موارد زیر اشاره کرد. مزایا:

  • • اشای همکار (Colleage) را از هم جدا می کند و وابستگی بین آنها را از بین می برد
  • • اشیا می توانند به راحتی وظایف خود را انجام دهند و بدون داشتن اطلاعات دقیق از اشیا دیگر با آنها ارتباط داشته باشند.
  • • کنترل ارتباطات با استفاده از این الگو متمرکز می شود.
  • • ارتباطات اشیا با یکدیگر به آسانی قابل فهم و استفاده مجدد خواهد بود.

معایب

  • • پیچیدگی کلاس mediator ممکن است بالا باشد.
  • • در صورت پیاده سازی نادرست ممکن است که فهم کلاس mediator سخت باشد.
  • الگوی Mediator یک الگوی رفتاری می باشد. 

الگوی Memento

در ادامه سری مقالات الگوهای طراحی قصد دارم که الگوی طراحی Memento رو شرح بدهم. این الگو را با نام Token نیز می شناسند. نام این الگو از روی یک فیلم برداشته شده است که عکس آن فیلم را ملاحظه می کنید. داستان این فیلم به این گونه بود که نقش اول این فیلم هیچ حافظه ای نداشت و مطالبی را که قصد به خاطر سپردن آن ها را داشت بر روی برگه های کوچکی یادداشت می کرد و از روی نوشته هایش تصمیم گیری می کرد.

این الگو نیز به همین شکل است. همان گونه که در الگوی Command توضیح دادیم می توان از الگوی Command برای پیاده سازی عمل undo استفاده کرد اما مکانیزم آن را به طور کامل شرح ندادیم. الگوی Command زمینه را برای پیاده سازی این عمل فراهم می کند ولی اطلاعاتی که در هر تغییر باید بازگردانی شوند باید با استفاده از الگوی Memento ذخیره گردند. الگوی memento همان مکانیزم یادداشت ها را در فیلم گفته شده فراهم می کند.

اهداف الگوی Memento

  1. بدون این که خللی در کپسوله سازی وارد کند حالت فعلی یک شی را دریافت و نگهداری می کند.
  2. حالت شی را بعد از این که ذخیره کرد هر وقت که نیاز داشته باشیم برمی گرداند. این ویژگی برای گرفتن Checkpoint و مکانیزم undo مفید است.

به طور کلی این الگو برای نگهداری وضعیت داخلی یک شی و ذخیره آن به صورت خارج کلاسی می باشد که بعدا بتوان این حالت شی را به وضعیت قبلی بازگرداند.

با سلام به همه دوستان و همراهان Itpro. در ادامه سری مقالات الگوهای طراحی قصد دارم که الگوی طراحی Memento رو شرح بدهم. این الگو را با نام Token نیز می شناسند. نام این الگو از روی یک فیلم برداشته شده است که عکس آن فیلم را ملاحظه می کنید. داستان این فیلم به این گونه بود که نقش اول این فیلم هیچ حافظه ای نداشت و مطالبی را که قصد به خاطر سپردن آن ها را داشت بر روی برگه های کوچکی یادداشت می کرد و از روی نوشته هایش تصمیم گیری می کرد. این الگو نیز به همین شکل است. همان گونه که در الگوی Command توضیح دادیم می توان از الگوی Command برای پیاده سازی عمل undo استفاده کرد اما مکانیزم آن را به طور کامل شرح ندادیم. الگوی Command زمینه را برای پیاده سازی این عمل فراهم می کند ولی اطلاعاتی که در هر تغییر باید بازگردانی شوند باید با استفاده از الگوی Memento ذخیره گردند. الگوی memento همان مکانیزم یادداشت ها را در فیلم گفته شده فراهم می کند.

!!اهداف این الگو
# بدون این که خللی در کپسوله سازی وارد کند حالت فعلی یک شی را دریافت و نگهداری می کند.
# حالت شی را بعد از این که ذخیره کرد هر وقت که نیاز داشته باشیم برمی گرداند. این ویژگی برای گرفتن Checkpoint و مکانیزم undo مفید است.
به طور کلی این الگو برای نگهداری وضعیت داخلی یک شی و ذخیره آن به صورت خارج کلاسی می باشد که بعدا بتوان این حالت شی را به وضعیت قبلی بازگرداند.
||http://tosinso.com/files/get/45767b6b-f068-4549-8373-c75a1c47b2ea||

!! شرح الگو
همه ی نرم افزارهای مدرن امروزه از قابلیتی به نام Undo استفاده می نمایند. این قابلیت به این صورت است که اگر ما کاری را در یک نرم افزار انجام داده باشیم و بخواهیم که برنامه این عمل ما را نادیده فرض کنید از این قابلیت استفاده می نماییم. و برنامه را به حالت قبل از عمل برمی گرداند. به طور مثال اگر در یک برنامه واژه پرداز (word processor) متنی را نوشته باشیم یا متنی را به عمد و یا غیر عمد حذف کرده باشیم ولی از انجام آن پشیمان شویم از قابلیت undo  استفاده می نماییم. همچنین در بازی های رایانه ای موجود وقتی به مرحله ی خاصی از بازی رسیدیم وضعیت بازی ذخیره می شود. که به هر قسمت ذخیره شده یک check point گفته می شود. ذخیره سازی وضعیت نرم افزار در برنامه گفته شده و check point بازی با استفاده از الگوی memento انجام می شود.

!!طراحی الگو (Design)
ذخیره وضعیت برنامه می تواند مستقل از خود شی باشد و این نکته کلیدی الگوی memento است. شکل نمودار uml این الگو در زیر آورده شده است:
||http://tosinso.com/files/get/ed120fb3-b171-40cc-9c30-b27eafefccff||
 کلاسی است که اشیا آن می توانند وضعیت خود را ذخیره کنند. این کلاس می تواند تصمیم بگیرد که هر بار چند تا از وضعیت ها ذخیره شوند. متغیر state شامل اطلاعات وضعیت شی originator است. این متغیری است که ما آن را ذخیره و بازیابی می کنیم. تابع CreateMemento برای ذخیره وضعیت originator استفاده می شود. این تابع یک شی Memento می سازد و شی state را با استفاده از آن ذخیره می نماید. تابع SetMemento شی وضعیت originator را با گرفتن شی Memento بر می گرداند. این تابع برای بازیابی وضعیت قبل می باشد که قبلا در شی memento ذخیره شده بود. کلاس Memento عمل ذخیره سازی وضعیت originator را به شکل تاریخچه ای انجام می دهد و Caretaker وضعیت های  ذخیره شده را در خود نگهداری می کند. به این شکل که لیستی از memento ها را در خود دارد. الگوی memento دارای دو واسط به شکل زیر است:

* یک واسط گسترده به سمت Originagtor که اجازه می دهد که به هر چیزی که می خواهد ذخیره کند دسترسی داشته باشد
* یک واسط محدود شده به سمت Caretaker که فقط می تواند به ارجاعات memento دسترسی داشته باشد. 

کلاس Memento وضعیت Originator را در خود نگهداری می کند ولی به کلاس های دیگر اجازه دسترسی به آن وضعیت را نمی دهد. با این کار محدودیت های کپسوله سازی (encapsulation) رعایت خواهد شد. دقت داشته باشید که شی کلاس memento هیچگاه توسط کاربر در دسترس نخواهد بود و همه ی اعمال توسط کلاس Caretaker انجام می شود. زیرا نحوه ذخیره و بازیابی به کلاس client مربوط نمی شود.

!!پیاده سازی
پیاده سازی این الگو در شکل زیر آمده است.
<c#>
class Program
{
    static void Main(string[] args)
    {
        Originator<string> orig = new Originator<string>();
orig.SetState(state0);
        Caretaker<string>.SaveState(orig); //save state of the originator
        orig.ShowState();
orig.SetState(state1);
        Caretaker<string>.SaveState(orig); //save state of the originator
        orig.ShowState();
orig.SetState(state2);
        Caretaker<string>.SaveState(orig); //save state of the originator
        orig.ShowState();
//restore state of the originator
        Caretaker<string>.RestoreState(orig, 0);
        orig.ShowState();  //shows state0
    }
}
//object that stores the historical state
public class Memento<t>
{
    private T state;
public T GetState()
    {
        return state;
    }
public void SetState(T state)
    {
        this.state = state;
    }
}
//the object that we want to save and restore, such as a check point in an application
public class Originator<t>
{
    private T state;
//for saving the state
    public Memento<t> CreateMemento()
    {
        Memento<t> m = new Memento<t>();
        m.SetState(state);
        return m;
    }
//for restoring the state
    public void SetMemento(Memento<t> m)
    {
        state = m.GetState();
    }
//change the state of the Originator
    public void SetState(T state)
    {
        this.state = state;
    }
//show the state of the Originator
    public void ShowState()
    {
        Console.WriteLine(state.ToString());
    }
}
//object for the client to access
public static class Caretaker<t>
{
    //list of states saved
    private static List<memento><t>> mementoList = new List<memento><t>>();
//save state of the originator
    public static void SaveState(Originator<t> orig)
    {
        mementoList.Add(orig.CreateMemento());
    }
//restore state of the originator
    public static void RestoreState(Originator<t> orig, int stateNumber)
    {
        orig.SetMemento(mementoList[stateNumber]);
    }
}

<c#>
نتیجه اجرای کد بالا به شکل زیر است:

عکس
امروزه از الگوی memento در بسیاری از نرم افزارها استفاده می شود و حتی برخی از کامپوننت های برنامه نویسی خود از این الگو استفاده می نمایند(مانند کنترل RichTextBox در سی شارپ که قابلیت undo دارد) ولی وقتی نیاز به این الگو حس می شود که در برخی پردازش های مهندسی که ممکن است چند روز طول بکشد، وسط اجرای پردازش مشکلی پیش بیاید و مجبور شویم پردازش را از سر بگیریم که باعث اتلاف وقت و هزینه بسیاری است. برای جلوگیری از این اتلاف هزینه و زمان از مکانیز گرفتن check point استفاده می شود که این مکانیزم هم برای پیاده سازی از الگوی memento استفاده می کند و در هر بار خرابی سیستم از آخرین check point کار را ادامه می دهد.*Itpro باشید.*


نویسنده : مهدی عادلی
منبع : |جزیره برنامه نویسی وب سایت توسینسو::https://programming.tosinso.com|
هرگونه نشر و کپی برداری بدون ذکر منبع و نام نویسنده دارای اشکال اخلاقی می باشد.

شرح الگوی Memento

همه ی نرم افزارهای مدرن امروزه از قابلیتی به نام Undo استفاده می نمایند. این قابلیت به این صورت است که اگر ما کاری را در یک نرم افزار انجام داده باشیم و بخواهیم که برنامه این عمل ما را نادیده فرض کنید از این قابلیت استفاده می نماییم. و برنامه را به حالت قبل از عمل برمی گرداند. به طور مثال اگر در یک برنامه واژه پرداز (word processor) متنی را نوشته باشیم

یا متنی را به عمد و یا غیر عمد حذف کرده باشیم ولی از انجام آن پشیمان شویم از قابلیت undo استفاده می نماییم. همچنین در بازی های رایانه ای موجود وقتی به مرحله ی خاصی از بازی رسیدیم وضعیت بازی ذخیره می شود. که به هر قسمت ذخیره شده یک check point گفته می شود. ذخیره سازی وضعیت نرم افزار در برنامه گفته شده و check point بازی با استفاده از الگوی memento انجام می شود.

طراحی الگو (Design) Memento

ذخیره وضعیت برنامه می تواند مستقل از خود شی باشد و این نکته کلیدی الگوی memento است. شکل نمودار uml این الگو در زیر آورده شده است:

با سلام به همه دوستان و همراهان Itpro. در ادامه سری مقالات الگوهای طراحی قصد دارم که الگوی طراحی Memento رو شرح بدهم. این الگو را با نام Token نیز می شناسند. نام این الگو از روی یک فیلم برداشته شده است که عکس آن فیلم را ملاحظه می کنید. داستان این فیلم به این گونه بود که نقش اول این فیلم هیچ حافظه ای نداشت و مطالبی را که قصد به خاطر سپردن آن ها را داشت بر روی برگه های کوچکی یادداشت می کرد و از روی نوشته هایش تصمیم گیری می کرد. این الگو نیز به همین شکل است. همان گونه که در الگوی Command توضیح دادیم می توان از الگوی Command برای پیاده سازی عمل undo استفاده کرد اما مکانیزم آن را به طور کامل شرح ندادیم. الگوی Command زمینه را برای پیاده سازی این عمل فراهم می کند ولی اطلاعاتی که در هر تغییر باید بازگردانی شوند باید با استفاده از الگوی Memento ذخیره گردند. الگوی memento همان مکانیزم یادداشت ها را در فیلم گفته شده فراهم می کند.

!!اهداف این الگو
# بدون این که خللی در کپسوله سازی وارد کند حالت فعلی یک شی را دریافت و نگهداری می کند.
# حالت شی را بعد از این که ذخیره کرد هر وقت که نیاز داشته باشیم برمی گرداند. این ویژگی برای گرفتن Checkpoint و مکانیزم undo مفید است.
به طور کلی این الگو برای نگهداری وضعیت داخلی یک شی و ذخیره آن به صورت خارج کلاسی می باشد که بعدا بتوان این حالت شی را به وضعیت قبلی بازگرداند.
||http://tosinso.com/files/get/45767b6b-f068-4549-8373-c75a1c47b2ea||

!! شرح الگو
همه ی نرم افزارهای مدرن امروزه از قابلیتی به نام Undo استفاده می نمایند. این قابلیت به این صورت است که اگر ما کاری را در یک نرم افزار انجام داده باشیم و بخواهیم که برنامه این عمل ما را نادیده فرض کنید از این قابلیت استفاده می نماییم. و برنامه را به حالت قبل از عمل برمی گرداند. به طور مثال اگر در یک برنامه واژه پرداز (word processor) متنی را نوشته باشیم یا متنی را به عمد و یا غیر عمد حذف کرده باشیم ولی از انجام آن پشیمان شویم از قابلیت undo  استفاده می نماییم. همچنین در بازی های رایانه ای موجود وقتی به مرحله ی خاصی از بازی رسیدیم وضعیت بازی ذخیره می شود. که به هر قسمت ذخیره شده یک check point گفته می شود. ذخیره سازی وضعیت نرم افزار در برنامه گفته شده و check point بازی با استفاده از الگوی memento انجام می شود.

!!طراحی الگو (Design)
ذخیره وضعیت برنامه می تواند مستقل از خود شی باشد و این نکته کلیدی الگوی memento است. شکل نمودار uml این الگو در زیر آورده شده است:
||http://tosinso.com/files/get/ed120fb3-b171-40cc-9c30-b27eafefccff||
 کلاسی است که اشیا آن می توانند وضعیت خود را ذخیره کنند. این کلاس می تواند تصمیم بگیرد که هر بار چند تا از وضعیت ها ذخیره شوند. متغیر state شامل اطلاعات وضعیت شی originator است. این متغیری است که ما آن را ذخیره و بازیابی می کنیم. تابع CreateMemento برای ذخیره وضعیت originator استفاده می شود. این تابع یک شی Memento می سازد و شی state را با استفاده از آن ذخیره می نماید. تابع SetMemento شی وضعیت originator را با گرفتن شی Memento بر می گرداند. این تابع برای بازیابی وضعیت قبل می باشد که قبلا در شی memento ذخیره شده بود. کلاس Memento عمل ذخیره سازی وضعیت originator را به شکل تاریخچه ای انجام می دهد و Caretaker وضعیت های  ذخیره شده را در خود نگهداری می کند. به این شکل که لیستی از memento ها را در خود دارد. الگوی memento دارای دو واسط به شکل زیر است:

* یک واسط گسترده به سمت Originagtor که اجازه می دهد که به هر چیزی که می خواهد ذخیره کند دسترسی داشته باشد
* یک واسط محدود شده به سمت Caretaker که فقط می تواند به ارجاعات memento دسترسی داشته باشد. 

کلاس Memento وضعیت Originator را در خود نگهداری می کند ولی به کلاس های دیگر اجازه دسترسی به آن وضعیت را نمی دهد. با این کار محدودیت های کپسوله سازی (encapsulation) رعایت خواهد شد. دقت داشته باشید که شی کلاس memento هیچگاه توسط کاربر در دسترس نخواهد بود و همه ی اعمال توسط کلاس Caretaker انجام می شود. زیرا نحوه ذخیره و بازیابی به کلاس client مربوط نمی شود.

!!پیاده سازی
پیاده سازی این الگو در شکل زیر آمده است.
<c#>
class Program
{
    static void Main(string[] args)
    {
        Originator<string> orig = new Originator<string>();
orig.SetState(state0);
        Caretaker<string>.SaveState(orig); //save state of the originator
        orig.ShowState();
orig.SetState(state1);
        Caretaker<string>.SaveState(orig); //save state of the originator
        orig.ShowState();
orig.SetState(state2);
        Caretaker<string>.SaveState(orig); //save state of the originator
        orig.ShowState();
//restore state of the originator
        Caretaker<string>.RestoreState(orig, 0);
        orig.ShowState();  //shows state0
    }
}
//object that stores the historical state
public class Memento<t>
{
    private T state;
public T GetState()
    {
        return state;
    }
public void SetState(T state)
    {
        this.state = state;
    }
}
//the object that we want to save and restore, such as a check point in an application
public class Originator<t>
{
    private T state;
//for saving the state
    public Memento<t> CreateMemento()
    {
        Memento<t> m = new Memento<t>();
        m.SetState(state);
        return m;
    }
//for restoring the state
    public void SetMemento(Memento<t> m)
    {
        state = m.GetState();
    }
//change the state of the Originator
    public void SetState(T state)
    {
        this.state = state;
    }
//show the state of the Originator
    public void ShowState()
    {
        Console.WriteLine(state.ToString());
    }
}
//object for the client to access
public static class Caretaker<t>
{
    //list of states saved
    private static List<memento><t>> mementoList = new List<memento><t>>();
//save state of the originator
    public static void SaveState(Originator<t> orig)
    {
        mementoList.Add(orig.CreateMemento());
    }
//restore state of the originator
    public static void RestoreState(Originator<t> orig, int stateNumber)
    {
        orig.SetMemento(mementoList[stateNumber]);
    }
}

<c#>
نتیجه اجرای کد بالا به شکل زیر است:

عکس
امروزه از الگوی memento در بسیاری از نرم افزارها استفاده می شود و حتی برخی از کامپوننت های برنامه نویسی خود از این الگو استفاده می نمایند(مانند کنترل RichTextBox در سی شارپ که قابلیت undo دارد) ولی وقتی نیاز به این الگو حس می شود که در برخی پردازش های مهندسی که ممکن است چند روز طول بکشد، وسط اجرای پردازش مشکلی پیش بیاید و مجبور شویم پردازش را از سر بگیریم که باعث اتلاف وقت و هزینه بسیاری است. برای جلوگیری از این اتلاف هزینه و زمان از مکانیز گرفتن check point استفاده می شود که این مکانیزم هم برای پیاده سازی از الگوی memento استفاده می کند و در هر بار خرابی سیستم از آخرین check point کار را ادامه می دهد.*Itpro باشید.*


نویسنده : مهدی عادلی
منبع : |جزیره برنامه نویسی وب سایت توسینسو::https://programming.tosinso.com|
هرگونه نشر و کپی برداری بدون ذکر منبع و نام نویسنده دارای اشکال اخلاقی می باشد.

کلاسی است که اشیا آن می توانند وضعیت خود را ذخیره کنند. این کلاس می تواند تصمیم بگیرد که هر بار چند تا از وضعیت ها ذخیره شوند. متغیر state شامل اطلاعات وضعیت شی originator است. این متغیری است که ما آن را ذخیره و بازیابی می کنیم. تابع CreateMemento برای ذخیره وضعیت originator استفاده می شود. این تابع یک شی Memento می سازد و شی state را با استفاده از آن ذخیره می نماید.

تابع SetMemento شی وضعیت originator را با گرفتن شی Memento بر می گرداند. این تابع برای بازیابی وضعیت قبل می باشد که قبلا در شی memento ذخیره شده بود. کلاس Memento عمل ذخیره سازی وضعیت originator را به شکل تاریخچه ای انجام می دهد و Caretaker وضعیت های ذخیره شده را در خود نگهداری می کند. به این شکل که لیستی از memento ها را در خود دارد. الگوی memento دارای دو واسط به شکل زیر است:

  • یک واسط گسترده به سمت Originagtor که اجازه می دهد که به هر چیزی که می خواهد ذخیره کند دسترسی داشته باشد
  • یک واسط محدود شده به سمت Caretaker که فقط می تواند به ارجاعات memento دسترسی داشته باشد.

کلاس Memento وضعیت Originator را در خود نگهداری می کند ولی به کلاس های دیگر اجازه دسترسی به آن وضعیت را نمی دهد. با این کار محدودیت های کپسوله سازی (encapsulation) رعایت خواهد شد. دقت داشته باشید که شی کلاس memento هیچگاه توسط کاربر در دسترس نخواهد بود و همه ی اعمال توسط کلاس Caretaker انجام می شود. زیرا نحوه ذخیره و بازیابی به کلاس client مربوط نمی شود.

پیاده سازی الگوی Memento

پیاده سازی این الگو در شکل زیر آمده است.

class Program
{
    static void Main(string[] args)
    {
        Originator<string> orig = new Originator<string>();
orig.SetState("state0");
        Caretaker<string>.SaveState(orig); //save state of the originator
        orig.ShowState();
orig.SetState("state1");
        Caretaker<string>.SaveState(orig); //save state of the originator
        orig.ShowState();
orig.SetState("state2");
        Caretaker<string>.SaveState(orig); //save state of the originator
        orig.ShowState();
//restore state of the originator
        Caretaker<string>.RestoreState(orig, 0);
        orig.ShowState();  //shows state0
    }
}
//object that stores the historical state
public class Memento<t>
{
    private T state;
public T GetState()
    {
        return state;
    }
public void SetState(T state)
    {
        this.state = state;
    }
}
//the object that we want to save and restore, such as a check point in an application
public class Originator<t>
{
    private T state;
//for saving the state
    public Memento<t> CreateMemento()
    {
        Memento<t> m = new Memento<t>();
        m.SetState(state);
        return m;
    }
//for restoring the state
    public void SetMemento(Memento<t> m)
    {
        state = m.GetState();
    }
//change the state of the Originator
    public void SetState(T state)
    {
        this.state = state;
    }
//show the state of the Originator
    public void ShowState()
    {
        Console.WriteLine(state.ToString());
    }
}
//object for the client to access
public static class Caretaker<t>
{
    //list of states saved
    private static List<memento><t>> mementoList = new List<memento><t>>();
//save state of the originator
    public static void SaveState(Originator<t> orig)
    {
        mementoList.Add(orig.CreateMemento());
    }
//restore state of the originator
    public static void RestoreState(Originator<t> orig, int stateNumber)
    {
        orig.SetMemento(mementoList[stateNumber]);
    }
}

نتیجه اجرای کد بالا به شکل زیر است:

عکس

امروزه از الگوی memento در بسیاری از نرم افزارها استفاده می شود و حتی برخی از کامپوننت های برنامه نویسی خود از این الگو استفاده می نمایند(مانند کنترل RichTextBox در سی شارپ که قابلیت undo دارد) ولی وقتی نیاز به این الگو حس می شود که در برخی پردازش های مهندسی که ممکن است چند روز طول بکشد

وسط اجرای پردازش مشکلی پیش بیاید و مجبور شویم پردازش را از سر بگیریم که باعث اتلاف وقت و هزینه بسیاری است. برای جلوگیری از این اتلاف هزینه و زمان از مکانیز گرفتن check point استفاده می شود که این مکانیزم هم برای پیاده سازی از الگوی memento استفاده می کند و در هر بار خرابی سیستم از آخرین check point کار را ادامه می دهد.

الگوی Strategy

در این مطلب قصد داریم که یکی دیگر از الگوهای طراحی شی گرا را شرح دهیم. الگویی که قصد توضیح آن را داریم الگوی Strategy می باشد. این الگو یک الگوی رفتاری یا Behavioral می باشد. الگوهای رفتاری با الگوریتم ها و ارتباط بین آن ها درگیر می باشند. اگر برنامه ما یک الگوریتم یکتا را پیاده سازی می کند گرچه ممکن است از چندین کلاس استفاده کند ولی به خاطر بالا رفتن پیچیدگی ممکن است که برای مدیریت برنامه و نگهداری کد مشکلاتی به جود بیاید. ما با استفاده از الگوهای طراحی رفتاری سعی می کنیم که از این پیچیدگی ها کم کنیم. حال به بررسی الگوی طراحی Strategy می پردازیم.

با سلام به همه دوستان و همراهان Itpro. در این مطلب قصد داریم که یکی دیگر از الگوهای طراحی شی گرا را شرح دهیم. الگویی که قصد توضیح آن را داریم الگوی Strategy می باشد. این الگو یک الگوی رفتاری یا Behavioral می باشد. الگوهای رفتاری با الگوریتم ها و ارتباط بین آن ها درگیر می باشند. اگر برنامه ما یک الگوریتم یکتا را پیاده سازی می کند گرچه ممکن است از چندین کلاس استفاده کند ولی به خاطر بالا رفتن پیچیدگی ممکن است که برای مدیریت برنامه و نگهداری کد مشکلاتی به جود بیاید. ما با استفاده از الگوهای طراحی رفتاری سعی می کنیم که از این پیچیدگی ها کم کنیم. حال به بررسی الگوی طراحی Strategy می پردازیم.
||http://tosinso.com/files/get/e2d4328b-0864-49b4-ac9c-4ca92ef5ed72||

!!الگوی طراحی Strategy
این الگو به این منظور استفاده می شود که یک الگوریتم را از کلاس میزبان جدا کرده و در کلاس دیگر نگهداری نماید. ممکن است که ما در برنامه خود چندین الگوریتم(استراتژی) داشته باشیم. حال اگر بخواهیم همه این الگوریتم ها را در برنامه خود داشته باشیم در صورت عادی باید از عبارات شرطی بسیاری استفاده کنید و همین عمل باعث می شود که پیچیدگی برنامه به شدت بالا برود. الگوی strategy کاربر را قادر می سازد که از داخل یک گروه از الگوریتم ها یک الگوریتم را برای استفاده انتخاب نماید.

!!شرح الگوریتم
اگر بخواهیم یک مثال ساده از الگوی Strategy بزنیم می توانیم برنامه ای را مثال بزنیم که با استفاده از روش های متفاوت مرتب سازی یک سری اعداد را مرتب سازی می کند. الگوریتم های  متفاوتی برای مرتب سازی وجود دارد که می توان به QuickSort و یا MergeSort اشاره کرد. هرکدام از این روش ها می توانند در شرایط خاصی بهترین انتخاب موجود باشند. می توان تصمیم گیری این شرایط را با استفاده از الگوی Strategy پیاده سازی نمود. به این شکل که یک مجموعه از ورودی ها را داریم. ولی هرکدام از روش های مرتب سازی را به صورت جداگانه پیاده سازی می کنیم. ولی ورودی ها و خروجی ها ی یکسانی داشته باشند. در این صورت با توجه به شرایط ورودی ها را به یک الگوریتم داده و خروجی آن را دریافت خواهیم کرد.

!! طراحی الگو
طراحی الگوی Strategy در قالب نمودار UML در شکل زیر نشان داده شده است. همانگونه که در شکل دیده می شود می توان از داخل استراتژی های موجود در یک گروه استراتژی مناسب انتخاب کرد.
||http://tosinso.com/files/get/92969101-bc8a-4eea-a61e-f6ac5e82d488||
کلاس هایی که در این الگو هستند به شرح زیر است:
* Context: کلاسی که اطلاعات ساختاری برای اشیا IStrategy را در خود نگه می دارد. همان قسمتی از برنامه است که نوع استراتژی را انتخاب می کند.
* IStrategy: یک اینترفیس مشترک بین همه ی استراتژی ها تعریف می کند.
* StartegyA,StrategyB کلاس هایی که شامل الگوریتم های پیاده شده از اینترفیس IStrategy می باشد.
کلاس Context یک شی از نوع استراتژی انتخاب شده می سازد. کلاس Strategy  ممکن است که به وضعیت Context دسترسی داشته باشد.

!!پیاده سازی
پیاده سازی برای الگوی Strategy نیازمند ویژگی های خاص و جدید C# نیست و می توان آن را به سادگی پیاده سازی کرد. در پیاده سازی کلاس Context یک نمونه از اینترفیس IStrategy ساخته می شود. کلاس استفاده کننده متد الگوریتم را از داخل Context فراخوانی می کند و این کلاس در خواست را به استراتژی مورد نظر هدایت می کند. در مثال زیر هر کدام از استراتژی ها یک متد move دارند و یک تولید کننده عدد تصادفی در کلاس استفاده کننده مشخص می کند که چه زمانی زمان تعویض الگوریتم می باشد. این مثال در کد زیر آورده شده است.
<c#>
using System;


// The Context
class Context {
// Context state
public const int start = 5;
 public int Counter = 5;

 // Strategy aggregation
 IStrategy strategy = new Strategy1( );

 // Algorithm invokes a strategy method
 public int Algorithm( ) {
 return strategy.Move(this);
 }

 // Changing strategies
 public void SwitchStrategy( ) {
 if (strategy is Strategy1)
 strategy = new Strategy2( );
 else
 strategy = new Strategy1( );
 }
 }

 // Strategy interface
 interface IStrategy {
 int Move (Context c);
 }
/ Strategy 1
 class Strategy1 : IStrategy {
 public int Move (Context c) {
 return ++c.Counter;
 }
 }

 // Strategy 2
 class Strategy2 : IStrategy {
 public int Move (Context c) {
 return --c.Counter ;
 }
 }

 // Client
 static class Program {
 static void Main ( ) {
 Context context = new Context( );
 context.SwitchStrategy( );
 Random r = new Random(37);
 for (int i=Context.start; i<=Context.start+15; i++) {
 if (r.Next(3) == 2) {
 Console.Write(|| );
 context.SwitchStrategy( );
 }
 Console.Write(context.Algorithm( ) + );
 }
 Console.WriteLine( );
 }
 }

<c#>

خروجی کد بالا به شکل زیر خواهد بود:
<text>
/* Output
65 4 || 5 6 7 || 6 || 7 8 9 10 || 9 8 7 6 || 7 || 6 5
66 */

<text>


برخی از نکات کلیدی درباره ی پیاده سازی الگوی Strategy عبارتند از:

* اغلب کلاس Context شامل عبارت switching یا تعویض الگوریتم یا چند دستور شرطی تو در تو می باشد تا در شرایط متفاوت تصمیماتی گرفته شود
* اگر استراتژی ها ساده هستند می توانند به شکل delegate پیاده سازی شوند و نیازی به ساختن کلاس نیست.
* اگر بخواهیم برنامه را بعدا گسترش دهیم و الگوریتم های جدیدی توسط کاربران به برنامه اضافه کنیم می توانیم از Extension method ها استفاده کنیم.

!!استفاده از الگو
یکی از موارد استفاده از الگوی Strategy استفاده از این الگو در پیاده سازی تکنولوژی Linq در زبان C# می باشد که می توان به راحتی برای انواع پایگاه های داده و انواع مجموعه داده ها از آن استفاده کرد.
به طور کلی در زمان های زیر از الگوی Strategy استفاده می کنیم.
# زمانی که کلاس های مرتبط زیادی داشته باشیم و این کلاس ها فقط در رفتارشان متفاوت باشند.
# زمانی که برای انجام کاری الگوریتم های متفاوتی موجود باشد و بتوان شرایط انتخاب الگوریتم را توسط کدنویسی مشخص کرد.
# زمانی که الگوریتم از داده هایی استفاده می کند که استفاده کننده ها نباید به آن کد دسترسی داشته باشند.

زمانی پیش می آید که Context نمی خواهد از هیچکدام از استراتژی های موجود استفاده کند در این صورت می گوییم که Context از استراتژی do nothing استفاده می کند. یعنی هیچ کاری انجام نمی دهد. *Itpro باشید.*


نویسنده : مهدی عادلی
منبع : |جزیره برنامه نویسی وب سایت توسینسو::https://programming.tosinso.com|
هرگونه نشر و کپی برداری بدون ذکر منبع و نام نویسنده دارای اشکال اخلاقی می باشد.

الگوی طراحی Strategy

این الگو به این منظور استفاده می شود که یک الگوریتم را از کلاس میزبان جدا کرده و در کلاس دیگر نگهداری نماید. ممکن است که ما در برنامه خود چندین الگوریتم(استراتژی) داشته باشیم. حال اگر بخواهیم همه این الگوریتم ها را در برنامه خود داشته باشیم در صورت عادی باید از عبارات شرطی بسیاری استفاده کنید و همین عمل باعث می شود که پیچیدگی برنامه به شدت بالا برود. الگوی strategy کاربر را قادر می سازد که از داخل یک گروه از الگوریتم ها یک الگوریتم را برای استفاده انتخاب نماید.

شرح الگوریتم الگوی Strategy

اگر بخواهیم یک مثال ساده از الگوی Strategy بزنیم می توانیم برنامه ای را مثال بزنیم که با استفاده از روش های متفاوت مرتب سازی یک سری اعداد را مرتب سازی می کند. الگوریتم های متفاوتی برای مرتب سازی وجود دارد که می توان به QuickSort و یا MergeSort اشاره کرد.

هرکدام از این روش ها می توانند در شرایط خاصی بهترین انتخاب موجود باشند. می توان تصمیم گیری این شرایط را با استفاده از الگوی Strategy پیاده سازی نمود. به این شکل که یک مجموعه از ورودی ها را داریم. ولی هرکدام از روش های مرتب سازی را به صورت جداگانه پیاده سازی می کنیم. ولی ورودی ها و خروجی ها ی یکسانی داشته باشند. در این صورت با توجه به شرایط ورودی ها را به یک الگوریتم داده و خروجی آن را دریافت خواهیم کرد.

طراحی الگوی Strategy

طراحی الگوی Strategy در قالب نمودار UML در شکل زیر نشان داده شده است. همانگونه که در شکل دیده می شود می توان از داخل استراتژی های موجود در یک گروه استراتژی مناسب انتخاب کرد.

با سلام به همه دوستان و همراهان Itpro. در این مطلب قصد داریم که یکی دیگر از الگوهای طراحی شی گرا را شرح دهیم. الگویی که قصد توضیح آن را داریم الگوی Strategy می باشد. این الگو یک الگوی رفتاری یا Behavioral می باشد. الگوهای رفتاری با الگوریتم ها و ارتباط بین آن ها درگیر می باشند. اگر برنامه ما یک الگوریتم یکتا را پیاده سازی می کند گرچه ممکن است از چندین کلاس استفاده کند ولی به خاطر بالا رفتن پیچیدگی ممکن است که برای مدیریت برنامه و نگهداری کد مشکلاتی به جود بیاید. ما با استفاده از الگوهای طراحی رفتاری سعی می کنیم که از این پیچیدگی ها کم کنیم. حال به بررسی الگوی طراحی Strategy می پردازیم.
||http://tosinso.com/files/get/e2d4328b-0864-49b4-ac9c-4ca92ef5ed72||

!!الگوی طراحی Strategy
این الگو به این منظور استفاده می شود که یک الگوریتم را از کلاس میزبان جدا کرده و در کلاس دیگر نگهداری نماید. ممکن است که ما در برنامه خود چندین الگوریتم(استراتژی) داشته باشیم. حال اگر بخواهیم همه این الگوریتم ها را در برنامه خود داشته باشیم در صورت عادی باید از عبارات شرطی بسیاری استفاده کنید و همین عمل باعث می شود که پیچیدگی برنامه به شدت بالا برود. الگوی strategy کاربر را قادر می سازد که از داخل یک گروه از الگوریتم ها یک الگوریتم را برای استفاده انتخاب نماید.

!!شرح الگوریتم
اگر بخواهیم یک مثال ساده از الگوی Strategy بزنیم می توانیم برنامه ای را مثال بزنیم که با استفاده از روش های متفاوت مرتب سازی یک سری اعداد را مرتب سازی می کند. الگوریتم های  متفاوتی برای مرتب سازی وجود دارد که می توان به QuickSort و یا MergeSort اشاره کرد. هرکدام از این روش ها می توانند در شرایط خاصی بهترین انتخاب موجود باشند. می توان تصمیم گیری این شرایط را با استفاده از الگوی Strategy پیاده سازی نمود. به این شکل که یک مجموعه از ورودی ها را داریم. ولی هرکدام از روش های مرتب سازی را به صورت جداگانه پیاده سازی می کنیم. ولی ورودی ها و خروجی ها ی یکسانی داشته باشند. در این صورت با توجه به شرایط ورودی ها را به یک الگوریتم داده و خروجی آن را دریافت خواهیم کرد.

!! طراحی الگو
طراحی الگوی Strategy در قالب نمودار UML در شکل زیر نشان داده شده است. همانگونه که در شکل دیده می شود می توان از داخل استراتژی های موجود در یک گروه استراتژی مناسب انتخاب کرد.
||http://tosinso.com/files/get/92969101-bc8a-4eea-a61e-f6ac5e82d488||
کلاس هایی که در این الگو هستند به شرح زیر است:
* Context: کلاسی که اطلاعات ساختاری برای اشیا IStrategy را در خود نگه می دارد. همان قسمتی از برنامه است که نوع استراتژی را انتخاب می کند.
* IStrategy: یک اینترفیس مشترک بین همه ی استراتژی ها تعریف می کند.
* StartegyA,StrategyB کلاس هایی که شامل الگوریتم های پیاده شده از اینترفیس IStrategy می باشد.
کلاس Context یک شی از نوع استراتژی انتخاب شده می سازد. کلاس Strategy  ممکن است که به وضعیت Context دسترسی داشته باشد.

!!پیاده سازی
پیاده سازی برای الگوی Strategy نیازمند ویژگی های خاص و جدید C# نیست و می توان آن را به سادگی پیاده سازی کرد. در پیاده سازی کلاس Context یک نمونه از اینترفیس IStrategy ساخته می شود. کلاس استفاده کننده متد الگوریتم را از داخل Context فراخوانی می کند و این کلاس در خواست را به استراتژی مورد نظر هدایت می کند. در مثال زیر هر کدام از استراتژی ها یک متد move دارند و یک تولید کننده عدد تصادفی در کلاس استفاده کننده مشخص می کند که چه زمانی زمان تعویض الگوریتم می باشد. این مثال در کد زیر آورده شده است.
<c#>
using System;


// The Context
class Context {
// Context state
public const int start = 5;
 public int Counter = 5;

 // Strategy aggregation
 IStrategy strategy = new Strategy1( );

 // Algorithm invokes a strategy method
 public int Algorithm( ) {
 return strategy.Move(this);
 }

 // Changing strategies
 public void SwitchStrategy( ) {
 if (strategy is Strategy1)
 strategy = new Strategy2( );
 else
 strategy = new Strategy1( );
 }
 }

 // Strategy interface
 interface IStrategy {
 int Move (Context c);
 }
/ Strategy 1
 class Strategy1 : IStrategy {
 public int Move (Context c) {
 return ++c.Counter;
 }
 }

 // Strategy 2
 class Strategy2 : IStrategy {
 public int Move (Context c) {
 return --c.Counter ;
 }
 }

 // Client
 static class Program {
 static void Main ( ) {
 Context context = new Context( );
 context.SwitchStrategy( );
 Random r = new Random(37);
 for (int i=Context.start; i<=Context.start+15; i++) {
 if (r.Next(3) == 2) {
 Console.Write(|| );
 context.SwitchStrategy( );
 }
 Console.Write(context.Algorithm( ) + );
 }
 Console.WriteLine( );
 }
 }

<c#>

خروجی کد بالا به شکل زیر خواهد بود:
<text>
/* Output
65 4 || 5 6 7 || 6 || 7 8 9 10 || 9 8 7 6 || 7 || 6 5
66 */

<text>


برخی از نکات کلیدی درباره ی پیاده سازی الگوی Strategy عبارتند از:

* اغلب کلاس Context شامل عبارت switching یا تعویض الگوریتم یا چند دستور شرطی تو در تو می باشد تا در شرایط متفاوت تصمیماتی گرفته شود
* اگر استراتژی ها ساده هستند می توانند به شکل delegate پیاده سازی شوند و نیازی به ساختن کلاس نیست.
* اگر بخواهیم برنامه را بعدا گسترش دهیم و الگوریتم های جدیدی توسط کاربران به برنامه اضافه کنیم می توانیم از Extension method ها استفاده کنیم.

!!استفاده از الگو
یکی از موارد استفاده از الگوی Strategy استفاده از این الگو در پیاده سازی تکنولوژی Linq در زبان C# می باشد که می توان به راحتی برای انواع پایگاه های داده و انواع مجموعه داده ها از آن استفاده کرد.
به طور کلی در زمان های زیر از الگوی Strategy استفاده می کنیم.
# زمانی که کلاس های مرتبط زیادی داشته باشیم و این کلاس ها فقط در رفتارشان متفاوت باشند.
# زمانی که برای انجام کاری الگوریتم های متفاوتی موجود باشد و بتوان شرایط انتخاب الگوریتم را توسط کدنویسی مشخص کرد.
# زمانی که الگوریتم از داده هایی استفاده می کند که استفاده کننده ها نباید به آن کد دسترسی داشته باشند.

زمانی پیش می آید که Context نمی خواهد از هیچکدام از استراتژی های موجود استفاده کند در این صورت می گوییم که Context از استراتژی do nothing استفاده می کند. یعنی هیچ کاری انجام نمی دهد. *Itpro باشید.*


نویسنده : مهدی عادلی
منبع : |جزیره برنامه نویسی وب سایت توسینسو::https://programming.tosinso.com|
هرگونه نشر و کپی برداری بدون ذکر منبع و نام نویسنده دارای اشکال اخلاقی می باشد.

کلاس هایی که در این الگو هستند به شرح زیر است:

  • Context: کلاسی که اطلاعات ساختاری برای اشیا IStrategy را در خود نگه می دارد. همان قسمتی از برنامه است که نوع استراتژی را انتخاب می کند.
  • IStrategy: یک اینترفیس مشترک بین همه ی استراتژی ها تعریف می کند.
  • StartegyA,StrategyB کلاس هایی که شامل الگوریتم های پیاده شده از اینترفیس IStrategy می باشد.

کلاس Context یک شی از نوع استراتژی انتخاب شده می سازد. کلاس Strategy ممکن است که به وضعیت Context دسترسی داشته باشد.

پیاده سازی الگوی Strategy

پیاده سازی برای الگوی Strategy نیازمند ویژگی های خاص و جدید C# نیست و می توان آن را به سادگی پیاده سازی کرد. در پیاده سازی کلاس Context یک نمونه از اینترفیس IStrategy ساخته می شود. کلاس استفاده کننده متد الگوریتم را از داخل Context فراخوانی می کند و این کلاس در خواست را به استراتژی مورد نظر هدایت می کند. در مثال زیر هر کدام از استراتژی ها یک متد move دارند و یک تولید کننده عدد تصادفی در کلاس استفاده کننده مشخص می کند که چه زمانی زمان تعویض الگوریتم می باشد. این مثال در کد زیر آورده شده است.

using System;


// The Context
class Context {
// Context state
public const int start = 5;
 public int Counter = 5;

 // Strategy aggregation
 IStrategy strategy = new Strategy1( );

 // Algorithm invokes a strategy method
 public int Algorithm( ) {
 return strategy.Move(this);
 }

 // Changing strategies
 public void SwitchStrategy( ) {
 if (strategy is Strategy1)
 strategy = new Strategy2( );
 else
 strategy = new Strategy1( );
 }
 }

 // Strategy interface
 interface IStrategy {
 int Move (Context c);
 }
/ Strategy 1
 class Strategy1 : IStrategy {
 public int Move (Context c) {
 return ++c.Counter;
 }
 }

 // Strategy 2
 class Strategy2 : IStrategy {
 public int Move (Context c) {
 return --c.Counter ;
 }
 }

 // Client
 static class Program {
 static void Main ( ) {
 Context context = new Context( );
 context.SwitchStrategy( );
 Random r = new Random(37);
 for (int i=Context.start; i<=Context.start+15; i++) {
 if (r.Next(3) == 2) {
 Console.Write("|| ");
 context.SwitchStrategy( );
 }
 Console.Write(context.Algorithm( ) +" ");
 }
 Console.WriteLine( );
 }
 }

خروجی کد بالا به شکل زیر خواهد بود:

/* Output
65 4 || 5 6 7 || 6 || 7 8 9 10 || 9 8 7 6 || 7 || 6 5
66 */

برخی از نکات کلیدی درباره ی پیاده سازی الگوی Strategy عبارتند از:

  • اغلب کلاس Context شامل عبارت switching یا تعویض الگوریتم یا چند دستور شرطی تو در تو می باشد تا در شرایط متفاوت تصمیماتی گرفته شود
  • اگر استراتژی ها ساده هستند می توانند به شکل delegate پیاده سازی شوند و نیازی به ساختن کلاس نیست.
  • اگر بخواهیم برنامه را بعدا گسترش دهیم و الگوریتم های جدیدی توسط کاربران به برنامه اضافه کنیم می توانیم از Extension method ها استفاده کنیم.

استفاده از الگوی Strategy

یکی از موارد استفاده از الگوی Strategy استفاده از این الگو در پیاده سازی تکنولوژی Linq در زبان C# می باشد که می توان به راحتی برای انواع پایگاه های داده و انواع مجموعه داده ها از آن استفاده کرد.

به طور کلی در زمان های زیر از الگوی Strategy استفاده می کنیم.

  1. زمانی که کلاس های مرتبط زیادی داشته باشیم و این کلاس ها فقط در رفتارشان متفاوت باشند.
  2. زمانی که برای انجام کاری الگوریتم های متفاوتی موجود باشد و بتوان شرایط انتخاب الگوریتم را توسط کدنویسی مشخص کرد.
  3. زمانی که الگوریتم از داده هایی استفاده می کند که استفاده کننده ها نباید به آن کد دسترسی داشته باشند.

زمانی پیش می آید که Context نمی خواهد از هیچکدام از استراتژی های موجود استفاده کند در این صورت می گوییم که Context از استراتژی do nothing استفاده می کند. یعنی هیچ کاری انجام نمی دهد.

آموزش دیزاین پترن (Design Patterns) قسمت 10 : الگوی Factory Method

در ادامه مباحث الگوهای طراحی شی گرا قصد داریم الگوی Factory Method را شرح خواهیم داد.

با سلام به همه دوستان و همراهان عزیز Itpro. در ادامه مباحث الگوهای طراحی شی گرا قصد داریم الگوی Factory Method را شرح خواهیم داد. 

||http://tosinso.com/files/get/f5677a16-bad1-4f01-a0df-cd22539a4d1a||

!!نقش الگو
الگوی Factory Method راهی برای ساخت اشیا می باشد و برای تولید اشیا از کلاس ها مورد استفاده قرار می گیرد. اما تفاوتی که وجود دارد این است که این الگو به زیرکلاس ها (subclass) اجازه می دهد که از کلاسی که مورد نظرشان است شی را بسازد. زیرکلاس های متفاوت ممکن است که پیاده سازی های متفاوتی داشته باشند. الگوی Factory Method با توجه به اطلاعات کاربر از آن زیرکلاسی که مدنظر است شیئی را می سازد.

!! شرح الگو
اگر یک میوه فروشی موجود باشد  که در کل روزهای سال میوه آوکادو می فروشد. این میوه فروشی باید  مطمئن باشد که می تواند در طول سال می تواند این میوه را از کشاورزان تهیه نماید. این میوه فروشی باید از نواحی و کشورهای مختلف این میوه را در طول سال خریده و در داخل فروشگاه عرضه نماید. این میوه در کشورهای اسپانیا، آفریقای جنوبی و کنیان در فصل های متفاوتی رشد می کند. الگوی Factory Method شبیه به این میوه فروشی عمل می کند.

!!طراحی الگو
طراحی این الگو به این شکل است که کاربر یک متغیر Product معرفی می کند و از Factory Method می خواهد که آن را مقدار دهی نماید. شیئی که ساخته می شود به این بستگی دارد که چه تصمیمی برای ساخت شی product گرفته شده است. نمودار uml این الگو به شکل زیر است. دقت کنید که در این نمودار دو نوع product به نام های productA و productB وجود دارد.
||http://tosinso.com/files/get/ca5b689e-224c-4b70-bbf9-237efd03ffee||
عناصری که در این نمودار وجود دارند به شرح زیر هستند:

*  IProduct: اینترفیسی برای کلاس Product
*  productA, productB: کلاس هایی که اینترفیس IProduct را پیاده سازی می کنند.
*  Creator کلاسی که الگوی Factory Method را می سازد
*  Factory Method تصمیم می گیرد که از کدام کلاس شی ساخته شود.

طراحی این الگو باعث می شود که بتوانیم در مورد این که کدام شی ساخته شود در یک زمان تصمیم گیری کنیم. نیازی نیست که کاربر بداند که زیرکلاس های مختلف را چگونه استفاده کند و فقط از اشیا ساخته شده استفاده می کند.

!!پیاده سازی و مثال: فراهم کردن میوه آوکادو
اگر بخواهیم برای این الگو یک مثال بیاوریم همان فراهم کردن میوه آوکادو را پیاده سازی می کنیم. اگر هرکدام از کشورهای تولید کننده آوکادو را به عنوان یک کلاس در نظر بگیریم و هرکدام اینترفیس IProduct را پیاده سازی می کند. بنابراین این کشورها می توانند آوکادو برای میوه فروشی فراهم کنند. کشورهای تولید کننده آوکادو با توجه به این که در کدام ماه از سال قرار داشته باشیم انتخاب می شوند. کد پیاده سازی و نتیجه آن به این شکل است.
<c#>
using System;
using System.Collections;

class FactoryPattern {

interface IProduct {
string ShipFrom( );
 }

 class ProductA : IProduct {
 public String ShipFrom ( ) {
 return  from South Africa;
 }
 }

 class ProductB : IProduct {
 public String ShipFrom ( ) {
 return from Spain;
 }
 }

 class DefaultProduct : IProduct {
 public String ShipFrom ( ) {
 return not available;
 }
 }

 class Creator {
 public IProduct FactoryMethod(int month) {
 if (month >= 4 && month <=11)
 return new ProductA( );
 else
 if (month == 1 || month == 2 || month == 12)
 return new ProductB( );
 else return new DefaultProduct( );
 }
 }

 static void Main( ) {
 Creator c = new Creator( );
 IProduct product;

 for (int i=1; i<=12; i++) {
 product = c.FactoryMethod(i);
 Console.WriteLine(Avocados +product.ShipFrom( ));
 }
 }
 }
<c#>
و نتیجه اجرای برنامه به شکل زیر خواهد شد
<text>
Avocados from Spain
Avocados from Spain
Avocados not available
Avocados from South Africa
Avocados from South Africa
Avocados from South Africa
Avocados from South Africa
Avocados from South Africa
Avocados from South Africa
Avocados from South Africa
Avocados from South Africa
Avocados from Spain
<text>
همانگونه که در کد دیده می شود این ما در متد main فقط از creator استفاده کرده ایم که این creator به اقتضای زمان تصمیم می گیرد که از کدام کلاس استفاده کند و هر کدام از کلاس ها یک متد ShipFrom دارند که آن را با توجه به نیاز خود پیاده سازی کرده اند.

!!موارد استفاده
از این الگو در موارد زیر استفاده می شود.
# زمانی که در برنامه ما انعطاف پذیری مهم باشد.
# اشیا بتوانند در زیرکلاس ها گسترش پیدا کنند
# دلیل مشخصی وجود دارد که یک زیرکلاس به زیرکلاس دیگر ارجحیت دارد- این منطق قسمتی از الگوی FactoryMethod  است. *Itpro باشید*


نویسنده : مهدی عادلی
منبع : |جزیره برنامه نویسی وب سایت توسینسو::https://programming.tosinso.com|
هرگونه نشر و کپی برداری بدون ذکر منبع و نام نویسنده دارای اشکال اخلاقی می باشد.

نقش الگوی Factory Method

الگوی Factory Method راهی برای ساخت اشیا می باشد و برای تولید اشیا از کلاس ها مورد استفاده قرار می گیرد. اما تفاوتی که وجود دارد این است که این الگو به زیرکلاس ها (subclass) اجازه می دهد که از کلاسی که مورد نظرشان است شی را بسازد. زیرکلاس های متفاوت ممکن است که پیاده سازی های متفاوتی داشته باشند. الگوی Factory Method با توجه به اطلاعات کاربر از آن زیرکلاسی که مدنظر است شیئی را می سازد.

شرح الگوی Factory Method

اگر یک میوه فروشی موجود باشد که در کل روزهای سال میوه آوکادو می فروشد. این میوه فروشی باید مطمئن باشد که می تواند در طول سال می تواند این میوه را از کشاورزان تهیه نماید. این میوه فروشی باید از نواحی و کشورهای مختلف این میوه را در طول سال خریده و در داخل فروشگاه عرضه نماید. این میوه در کشورهای اسپانیا، آفریقای جنوبی و کنیان در فصل های متفاوتی رشد می کند. الگوی Factory Method شبیه به این میوه فروشی عمل می کند.

طراحی الگوی Factory Method

طراحی این الگو به این شکل است که کاربر یک متغیر Product معرفی می کند و از Factory Method می خواهد که آن را مقدار دهی نماید. شیئی که ساخته می شود به این بستگی دارد که چه تصمیمی برای ساخت شی product گرفته شده است. نمودار uml این الگو به شکل زیر است. دقت کنید که در این نمودار دو نوع product به نام های productA و productB وجود دارد.

با سلام به همه دوستان و همراهان عزیز Itpro. در ادامه مباحث الگوهای طراحی شی گرا قصد داریم الگوی Factory Method را شرح خواهیم داد. 

||http://tosinso.com/files/get/f5677a16-bad1-4f01-a0df-cd22539a4d1a||

!!نقش الگو
الگوی Factory Method راهی برای ساخت اشیا می باشد و برای تولید اشیا از کلاس ها مورد استفاده قرار می گیرد. اما تفاوتی که وجود دارد این است که این الگو به زیرکلاس ها (subclass) اجازه می دهد که از کلاسی که مورد نظرشان است شی را بسازد. زیرکلاس های متفاوت ممکن است که پیاده سازی های متفاوتی داشته باشند. الگوی Factory Method با توجه به اطلاعات کاربر از آن زیرکلاسی که مدنظر است شیئی را می سازد.

!! شرح الگو
اگر یک میوه فروشی موجود باشد  که در کل روزهای سال میوه آوکادو می فروشد. این میوه فروشی باید  مطمئن باشد که می تواند در طول سال می تواند این میوه را از کشاورزان تهیه نماید. این میوه فروشی باید از نواحی و کشورهای مختلف این میوه را در طول سال خریده و در داخل فروشگاه عرضه نماید. این میوه در کشورهای اسپانیا، آفریقای جنوبی و کنیان در فصل های متفاوتی رشد می کند. الگوی Factory Method شبیه به این میوه فروشی عمل می کند.

!!طراحی الگو
طراحی این الگو به این شکل است که کاربر یک متغیر Product معرفی می کند و از Factory Method می خواهد که آن را مقدار دهی نماید. شیئی که ساخته می شود به این بستگی دارد که چه تصمیمی برای ساخت شی product گرفته شده است. نمودار uml این الگو به شکل زیر است. دقت کنید که در این نمودار دو نوع product به نام های productA و productB وجود دارد.
||http://tosinso.com/files/get/ca5b689e-224c-4b70-bbf9-237efd03ffee||
عناصری که در این نمودار وجود دارند به شرح زیر هستند:

*  IProduct: اینترفیسی برای کلاس Product
*  productA, productB: کلاس هایی که اینترفیس IProduct را پیاده سازی می کنند.
*  Creator کلاسی که الگوی Factory Method را می سازد
*  Factory Method تصمیم می گیرد که از کدام کلاس شی ساخته شود.

طراحی این الگو باعث می شود که بتوانیم در مورد این که کدام شی ساخته شود در یک زمان تصمیم گیری کنیم. نیازی نیست که کاربر بداند که زیرکلاس های مختلف را چگونه استفاده کند و فقط از اشیا ساخته شده استفاده می کند.

!!پیاده سازی و مثال: فراهم کردن میوه آوکادو
اگر بخواهیم برای این الگو یک مثال بیاوریم همان فراهم کردن میوه آوکادو را پیاده سازی می کنیم. اگر هرکدام از کشورهای تولید کننده آوکادو را به عنوان یک کلاس در نظر بگیریم و هرکدام اینترفیس IProduct را پیاده سازی می کند. بنابراین این کشورها می توانند آوکادو برای میوه فروشی فراهم کنند. کشورهای تولید کننده آوکادو با توجه به این که در کدام ماه از سال قرار داشته باشیم انتخاب می شوند. کد پیاده سازی و نتیجه آن به این شکل است.
<c#>
using System;
using System.Collections;

class FactoryPattern {

interface IProduct {
string ShipFrom( );
 }

 class ProductA : IProduct {
 public String ShipFrom ( ) {
 return  from South Africa;
 }
 }

 class ProductB : IProduct {
 public String ShipFrom ( ) {
 return from Spain;
 }
 }

 class DefaultProduct : IProduct {
 public String ShipFrom ( ) {
 return not available;
 }
 }

 class Creator {
 public IProduct FactoryMethod(int month) {
 if (month >= 4 && month <=11)
 return new ProductA( );
 else
 if (month == 1 || month == 2 || month == 12)
 return new ProductB( );
 else return new DefaultProduct( );
 }
 }

 static void Main( ) {
 Creator c = new Creator( );
 IProduct product;

 for (int i=1; i<=12; i++) {
 product = c.FactoryMethod(i);
 Console.WriteLine(Avocados +product.ShipFrom( ));
 }
 }
 }
<c#>
و نتیجه اجرای برنامه به شکل زیر خواهد شد
<text>
Avocados from Spain
Avocados from Spain
Avocados not available
Avocados from South Africa
Avocados from South Africa
Avocados from South Africa
Avocados from South Africa
Avocados from South Africa
Avocados from South Africa
Avocados from South Africa
Avocados from South Africa
Avocados from Spain
<text>
همانگونه که در کد دیده می شود این ما در متد main فقط از creator استفاده کرده ایم که این creator به اقتضای زمان تصمیم می گیرد که از کدام کلاس استفاده کند و هر کدام از کلاس ها یک متد ShipFrom دارند که آن را با توجه به نیاز خود پیاده سازی کرده اند.

!!موارد استفاده
از این الگو در موارد زیر استفاده می شود.
# زمانی که در برنامه ما انعطاف پذیری مهم باشد.
# اشیا بتوانند در زیرکلاس ها گسترش پیدا کنند
# دلیل مشخصی وجود دارد که یک زیرکلاس به زیرکلاس دیگر ارجحیت دارد- این منطق قسمتی از الگوی FactoryMethod  است. *Itpro باشید*


نویسنده : مهدی عادلی
منبع : |جزیره برنامه نویسی وب سایت توسینسو::https://programming.tosinso.com|
هرگونه نشر و کپی برداری بدون ذکر منبع و نام نویسنده دارای اشکال اخلاقی می باشد.

عناصری که در این نمودار وجود دارند به شرح زیر هستند:

  • IProduct: اینترفیسی برای کلاس Product
  • productA, productB: کلاس هایی که اینترفیس IProduct را پیاده سازی می کنند.
  • Creator کلاسی که الگوی Factory Method را می سازد
  • Factory Method تصمیم می گیرد که از کدام کلاس شی ساخته شود.

طراحی این الگو باعث می شود که بتوانیم در مورد این که کدام شی ساخته شود در یک زمان تصمیم گیری کنیم. نیازی نیست که کاربر بداند که زیرکلاس های مختلف را چگونه استفاده کند و فقط از اشیا ساخته شده استفاده می کند.

پیاده سازی و مثال: فراهم کردن میوه آوکادو

اگر بخواهیم برای این الگو یک مثال بیاوریم همان فراهم کردن میوه آوکادو را پیاده سازی می کنیم. اگر هرکدام از کشورهای تولید کننده آوکادو را به عنوان یک کلاس در نظر بگیریم و هرکدام اینترفیس IProduct را پیاده سازی می کند. بنابراین این کشورها می توانند آوکادو برای میوه فروشی فراهم کنند. کشورهای تولید کننده آوکادو با توجه به این که در کدام ماه از سال قرار داشته باشیم انتخاب می شوند. کد پیاده سازی و نتیجه آن به این شکل است.

using System;
using System.Collections;

class FactoryPattern {

interface IProduct {
string ShipFrom( );
 }

 class ProductA : IProduct {
 public String ShipFrom ( ) {
 return " from South Africa";
 }
 }

 class ProductB : IProduct {
 public String ShipFrom ( ) {
 return "from Spain";
 }
 }

 class DefaultProduct : IProduct {
 public String ShipFrom ( ) {
 return "not available";
 }
 }

 class Creator {
 public IProduct FactoryMethod(int month) {
 if (month >= 4 && month <=11)
 return new ProductA( );
 else
 if (month == 1 || month == 2 || month == 12)
 return new ProductB( );
 else return new DefaultProduct( );
 }
 }

 static void Main( ) {
 Creator c = new Creator( );
 IProduct product;

 for (int i=1; i<=12; i++) {
 product = c.FactoryMethod(i);
 Console.WriteLine("Avocados "+product.ShipFrom( ));
 }
 }
 }

و نتیجه اجرای برنامه به شکل زیر خواهد شد

Avocados from Spain
Avocados from Spain
Avocados not available
Avocados from South Africa
Avocados from South Africa
Avocados from South Africa
Avocados from South Africa
Avocados from South Africa
Avocados from South Africa
Avocados from South Africa
Avocados from South Africa
Avocados from Spain

همانگونه که در کد دیده می شود این ما در متد main فقط از creator استفاده کرده ایم که این creator به اقتضای زمان تصمیم می گیرد که از کدام کلاس استفاده کند و هر کدام از کلاس ها یک متد ShipFrom دارند که آن را با توجه به نیاز خود پیاده سازی کرده اند.

موارد استفاده الگوی Factory Method

از این الگو در موارد زیر استفاده می شود.

  1. زمانی که در برنامه ما انعطاف پذیری مهم باشد.
  2. اشیا بتوانند در زیرکلاس ها گسترش پیدا کنند
  3. دلیل مشخصی وجود دارد که یک زیرکلاس به زیرکلاس دیگر ارجحیت دارد- این منطق قسمتی از الگوی FactoryMethod است.

الگوی State

در ادامه مباحث الگوهای طراحی در این مطلب قصد دارم که به الگوی state بپردازم، امیدوارم که مفید باشد. الگوی state یک الگوی رفتاری می باشد. این الگو سازوکاری میچیند که ارتباطات بین کلاس ها و موجودیت ها کنترل شود. این الگو را می توان نسخه پویا و دینامیک الگوی strategy دانست. رفتار این الگو به این شکل است که وقتی که حالت داخلی یک شی تغییر می کند با توجه به آن تغییر این الگو رفتار خود را تغییر می دهد. این تغییر با تغییر اعمال درون الگو می باشد. این عمل در صورتی قابل انجام است که برای یک شی تعریف شده زیر کلاس (subclass) آن را تغییر بدهیم.

شرح الگوی State

یک برنامه پرواز را در نظر بگیرید که توسط یک شرکت هواپیمایی استفاده می شود. کار این برنام به این شکل است که هر مسافر که برای اولین بار برای پرواز به این شرکت می آید در وضعیت آبی قرار دارد. سیستم برای مسافران وضعیت آبی امکانات و تسهیلات خاصی در نظر می گیرد. و قیمت پرواز را برای آنان به گونه ای حساب می کند که تخفیف ندارد و همچنین مسافت پروازی آنان نیز محدود است.

بعد از 5 پرواز که همان مسافر با این شرکت هواپیمایی انجام داد و پروازش در این سیستم ثبت شد مسافر از وضعیت آبی به وضعیت نقره ای ارتقاع پیدا می کند. سیستم برای مسافران وضعیت نقره ای برای هر پرواز 5 درصد تخفیف در نظر می گیرد و همچنین مسافت پرواز را به اندازه ای افزایش می دهد. حال اگر شخصی بیش از 15 پرواز انجام داده باشد به وضعیت طلایی خواهد رسید و برای هر پرواز 15 درصد تخیفیف خواهد گرفت.

دقت کنید که مسافر باید این پرواز ها را در طول یک سال انجام دهد. حال وضعیت مسافر را توسط الگوی State پیاده سازی می کنیم. در الگوی State رفتار کلاس با توجه به حالت (State) کلاس تغییر می کند. این الگو یک الگوی رفتاری است. در این الگو ما اشیائی را می سازیم که حالت های مختلف یک کلاس را دارا می باشد.

طراحی الگوی State

الگوی State بین کلاس Context و State یک تعامل جالب ایجاد می کند. کلاس Context شامل اطلاعاتی است که اکثرا ثابت است در حالی که State می تواند در طی اجرای برنامه تغییر کند. کلاس UML این ای الگو به شکل زیر است.

با سلام به همه دوستان و همراهان Itpro. در ادامه مباحث الگوهای طراحی در این مطلب قصد دارم که به الگوی state بپردازم، امیدوارم که مفید باشد. الگوی state یک الگوی رفتاری می باشد. این الگو سازوکاری میچیند که ارتباطات بین کلاس ها و موجودیت ها کنترل شود. این الگو را می توان نسخه پویا و دینامیک الگوی strategy دانست. رفتار این الگو به این شکل است که وقتی که حالت داخلی یک شی تغییر می کند با توجه به آن تغییر این الگو رفتار خود را تغییر می دهد. این تغییر با تغییر اعمال درون الگو می باشد. این عمل در صورتی قابل انجام است که برای یک شی تعریف شده زیر کلاس (subclass) آن را تغییر بدهیم.

!!شرح الگو
یک برنامه پرواز را در نظر بگیرید که توسط یک شرکت هواپیمایی استفاده می شود. کار این برنام به این شکل است که هر مسافر که برای اولین بار برای پرواز به این شرکت می آید در وضعیت آبی قرار دارد. سیستم برای مسافران وضعیت آبی امکانات و تسهیلات خاصی در نظر می گیرد. و قیمت پرواز را برای آنان به گونه ای حساب می کند که تخفیف ندارد و همچنین مسافت پروازی آنان نیز محدود است. بعد از 5 پرواز که همان مسافر با این شرکت هواپیمایی انجام داد و پروازش در این سیستم ثبت شد مسافر از وضعیت آبی به وضعیت نقره ای ارتقاع پیدا می کند. سیستم برای مسافران وضعیت نقره ای برای هر پرواز 5 درصد تخفیف در نظر می گیرد و همچنین مسافت پرواز را به اندازه ای افزایش می دهد. حال اگر شخصی بیش از 15 پرواز انجام داده باشد به وضعیت طلایی خواهد رسید و برای هر پرواز 15 درصد تخیفیف خواهد گرفت. دقت کنید که مسافر باید این پرواز ها را در طول یک سال انجام دهد. حال وضعیت مسافر را توسط الگوی State پیاده  سازی می کنیم. در الگوی State رفتار کلاس با توجه به حالت (State)  کلاس تغییر می کند. این الگو یک الگوی رفتاری است. در این الگو ما اشیائی را می سازیم که حالت های مختلف یک کلاس را دارا می باشد.

!!طراحی الگوی State
الگوی State بین کلاس Context و State یک تعامل جالب ایجاد می کند. کلاس Context شامل اطلاعاتی است که اکثرا ثابت است در حالی که State می تواند در طی اجرای برنامه تغییر کند. کلاس UML این ای الگو به شکل زیر است.
||http://tosinso.com/files/get/b06246f1-bbc7-4f6a-bd0e-d010bbd0b870||
همانطور که در شکل مشاهده می شود اجزای این الگو عبارتند از:
* Context کلاسی که یک شی از State را نگهداری می کند.
* IState یک اینترفیس برای حالت های Context تعریف می کند.
* StateA و StateB کلاس هایی که حالت هایی از Context را دارا می باشند. 
کلاس Context یک متغیر از نوع IState در خود دارد که به یک شی خاص (مثل stateA) اشاره می کند.  همه ی عملیات از طریق متد Handle انجام می شوند. همانطور که در شکل دیده می شود کلاس State به داده های Context دسترسی کامل دارد. بنابراین در هر زمانی هم کلاس Context و هم شی State می توانند تصمیم بگیرند که تغییر حالت بدهند. این کار با انتساب ویژگی های state جدید به شی Context صورت می گیرد. وقتی که این کار انجام شود همه ی درخواست ها به state جدید ارسال می شوند. که ممکن است اعمالی که در این State انجام می شود با اعمال State قبلی کاملا متفاوت باشد.

!!پیاده سازی
همانند الگوی استراتژی الگوی State هم به مکانیزم اینترفیس و تجمع بستگی دارد. در مثال زیر دو کلاس state به نام های NormalState و FastState وجود دارد که برای شمارش شمارنده داخل کلاس Context با سرعت های متفاوتی عمل می کنند.  هر دو کلاس اینترفیس IState را پیاده سازی می کنند و هردو کلاس ها دارای دو تابع MoveUpو MoveDown هستند. خود state ها تصمیم می گیرند که چه زمانی به state دیگر سوییچ کنند. در این مثال بر پایه مقدار عددی شماره تصمیم گیری می شود. 
<c#>
using System;
using System.Collections.Generic;
interface IState {
 int MoveUp(Context context);
int MoveDown(Context context);
}

// State 1
class NormalState : IState {
public int MoveUp(Context context) {
context.Counter+=2;
return context.Counter;
}

public int MoveDown(Context context) {
if (context.Counter < Context.limit) {
context.State = new FastState( );
Console.Write(|| );
}
context.Counter-=2;
return context.Counter;
}
}

// State 2
class FastState : IState {
public int MoveUp(Context context) {
context.Counter+=5;
return context.Counter;

}

public int MoveDown(Context context) {
if (context.Counter < Context.limit) {
context.State = new NormalState( );
Console.Write(||);
}
context.Counter-=5;
return context.Counter;
}
}

// Context
class Context {
public const int limit = 10;
public IState State {get; set; }
public int Counter = limit;
public int Request(int n) {
if (n==2)
return State.MoveUp(this);
else
return State.MoveDown(this);
}
}

static class Program {
// The user interface
static void Main ( ) {
Context context = new Context( );
context.State = new NormalState( );
Random r = new Random(37);
for (int i = 5; i<=25; i++) {
int command = r.Next(3);
Console.Write(context.Request(command)+ );
}
Console.WriteLine( );
}
}
<c#>
خروجی این کد به شکل زیر خواهد بود
<text>
8 10 8 || 6 11 16 11 6 ||1 3 || 1 ||-4 || -6 -1 4 ||-1 || -3 2 7 ||2 4
<text>
دقت کنید که علامت || در خروجی نشان دهنده محل تغییر state می باشد. مسئله ای که قابل تامل است این است که آیا ما اشیا State را د آغاز برنامه بسازیم یا ساخت آنها را به زمان نیاز داشتن به آن اشیا موکول کنیم. انجام این کار بستگی به تعداد دفعات تغییر حالت در برنامه و اندازه داده شی State بستگی دارد. برای حالت هایی که تغییرات زیادی داریم بهتر است که شی را از همان ابتدا بسازیم.

!!موارد استفاده
این الگو برای پیاده سازی ابزارهای گرافیکی مورد استفاده قرار بگیرد و در کل برای اشیائی که باید در زمان اجرا تغییر کند. همچنین برای اشیایی که در حال پیچیده شدن هستند و شرط های زیادی دارند قابل استفاده است. *ITPro باشید*

نویسنده : مهدی عادلی
منبع : |جزیره برنامه نویسی وب سایت توسینسو::https://programming.tosinso.com|
هرگونه نشر و کپی برداری بدون ذکر منبع و نام نویسنده دارای اشکال اخلاقی می باشد.

همانطور که در شکل مشاهده می شود اجزای این الگو عبارتند از:

  • Context کلاسی که یک شی از State را نگهداری می کند.
  • IState یک اینترفیس برای حالت های Context تعریف می کند.
  • StateA و StateB کلاس هایی که حالت هایی از Context را دارا می باشند.

کلاس Context یک متغیر از نوع IState در خود دارد که به یک شی خاص (مثل stateA) اشاره می کند. همه ی عملیات از طریق متد Handle انجام می شوند. همانطور که در شکل دیده می شود کلاس State به داده های Context دسترسی کامل دارد. بنابراین در هر زمانی هم کلاس Context و هم شی State می توانند تصمیم بگیرند که تغییر حالت بدهند. این کار با انتساب ویژگی های state جدید به شی Context صورت می گیرد. وقتی که این کار انجام شود همه ی درخواست ها به state جدید ارسال می شوند. که ممکن است اعمالی که در این State انجام می شود با اعمال State قبلی کاملا متفاوت باشد.

پیاده سازی الگوی State

همانند الگوی استراتژی الگوی State هم به مکانیزم اینترفیس و تجمع بستگی دارد. در مثال زیر دو کلاس state به نام های NormalState و FastState وجود دارد که برای شمارش شمارنده داخل کلاس Context با سرعت های متفاوتی عمل می کنند. هر دو کلاس اینترفیس IState را پیاده سازی می کنند و هردو کلاس ها دارای دو تابع MoveUpو MoveDown هستند. خود state ها تصمیم می گیرند که چه زمانی به state دیگر سوییچ کنند. در این مثال بر پایه مقدار عددی شماره تصمیم گیری می شود.

using System;
using System.Collections.Generic;
interface IState {
 int MoveUp(Context context);
int MoveDown(Context context);
}

// State 1
class NormalState : IState {
public int MoveUp(Context context) {
context.Counter+=2;
return context.Counter;
}

public int MoveDown(Context context) {
if (context.Counter < Context.limit) {
context.State = new FastState( );
Console.Write("|| ");
}
context.Counter-=2;
return context.Counter;
}
}

// State 2
class FastState : IState {
public int MoveUp(Context context) {
context.Counter+=5;
return context.Counter;

}

public int MoveDown(Context context) {
if (context.Counter < Context.limit) {
context.State = new NormalState( );
Console.Write("||");
}
context.Counter-=5;
return context.Counter;
}
}

// Context
class Context {
public const int limit = 10;
public IState State {get; set; }
public int Counter = limit;
public int Request(int n) {
if (n==2)
return State.MoveUp(this);
else
return State.MoveDown(this);
}
}

static class Program {
// The user interface
static void Main ( ) {
Context context = new Context( );
context.State = new NormalState( );
Random r = new Random(37);
for (int i = 5; i<=25; i++) {
int command = r.Next(3);
Console.Write(context.Request(command)+" ");
}
Console.WriteLine( );
}
}

خروجی این کد به شکل زیر خواهد بود

8 10 8 || 6 11 16 11 6 ||1 3 || 1 ||-4 || -6 -1 4 ||-1 || -3 2 7 ||2 4

دقت کنید که علامت || در خروجی نشان دهنده محل تغییر state می باشد. مسئله ای که قابل تامل است این است که آیا ما اشیا State را د آغاز برنامه بسازیم یا ساخت آنها را به زمان نیاز داشتن به آن اشیا موکول کنیم. انجام این کار بستگی به تعداد دفعات تغییر حالت در برنامه و اندازه داده شی State بستگی دارد. برای حالت هایی که تغییرات زیادی داریم بهتر است که شی را از همان ابتدا بسازیم.

موارد استفاده الگوی State

این الگو برای پیاده سازی ابزارهای گرافیکی مورد استفاده قرار بگیرد و در کل برای اشیائی که باید در زمان اجرا تغییر کند. همچنین برای اشیایی که در حال پیچیده شدن هستند و شرط های زیادی دارند قابل استفاده است.

  • دیزاین پترن | Design Pattern چیست؟

    در مهندسی نرم افزار ، دیزاین پترن | Design Pattern به یک راهکار مدیریت خطاهای تکراری در طراحی نرم افزار گفته می شود . در این مقاله ما بصورت مفصل تمامی الگوریتم ها و الگوهای دیزاین پترن را بررسی می کنیم.

مهدی عادلی فر
مهدی عادلی فر

بنیانگذار توسینسو و برنامه نویس

مهدی عادلی، بنیان گذار TOSINSO. کارشناس ارشد نرم افزار کامپیوتر از دانشگاه صنعتی امیرکبیر و #C و جاوا و اندروید کار می کنم. در زمینه های موبایل و وب و ویندوز فعالیت دارم و به طراحی نرم افزار و اصول مهندسی نرم افزار علاقه مندم.

نظرات