تعمق اولیه‌ای بر الگو‌های طراحی GoF

چکیدهکتاب دسته‌ی چهار نفره، شامل الگوهای طراحی است که راه‌حل‌های ساده و ظریفی را برای مشکلات مشخصی در حوزه‌ی طراحی شی‌گرای نرم‌افزار توصیف می‌کنند. یک الگو به معنای یک دوتاییِ مشکل-راه‌حل در یک زمینه خاص می‌باشد. به این ترتیب، الگوهای طراحیِ دسته‌ی چهار نفره نیز راه‌حل‌هایی با قابلیت استفاده مجدد برای مشکلات تکرارشونده‌ی پارادیمِ شی‌گرا می‌باشند.تا کنون انشاها و مقالات بسیاری ذیل الگوهای طراحی دسته‌ی چهار نفره منتشر شده‌اند که صرف الگوها را مورد بررسی قرار می‌دهند. از این رو در این تحقیق سعی شده است برای دانش «طراحی شی‌گرا»یی - که به منظور درک عمیق‌تر الگو‌های دسته‌ی چهار نفره لازم است - توضیحی ارائه شود.در بخش اول این تحقیق پیش‌نیازهای دانش شی‌گرا با قرائت‌کننده به اشتراک گذاشته می‌شوند و فرض شده است خواننده‌ی این نگارش، دانش سطحی از حداقل یک زبان برنامه‌نویسی شی‌گرا را داراست. موارد زیر مشمول توضیحات بخش اول خواهند بود:اصول شی‌گرا: شامل پنج اصل معروفِ SOLID به همراه دو اصل PLK و CRP.الگو‌های GRASP.در بخش دوم، چند مورد از الگوهای طراحی دسته‌ی چهار نفره بررسی می‌شوند و در تشریح آن‌ها به اصول و الگوهایی از بخش اول ارجاع خواهد شد.در انتهای این تحقیق یک واژه‌نامه به منظور بازگردانی لغت‌های کلیدی مورد استفاده این تحقیق، از انگلیسی به فارسی، قرار داده شده است؛ پیشنهاد می‌شود قرائت‌کننده پیش از مطالعه بخش‌های بعدی تحقیق حداقل یکبار آن‌ها را مطالعه کند. معادل انگلیسی باقی واژه‌های بازگردانی شده در طول تحقیق به صورت پانویس مکتوب شده‌اند.مقدمهکتاب دسته‌ی چهار نفره، شامل الگوهای طراحی است که راه‌حل‌های ساده و ظریفی را برای مشکلات مشخصی در حوزه‌ی طراحی شی‌گرای نرم‌افزار توصیف می‌کنند. این الگوها - طبق گفته واضعان این کتاب -، جدید، به معنای آن که در هنگامِ نگارش این کتاب تولید شده باشند، نیستند. هر الگو پیش از نگارش این کتاب کشف، کارآمدی آن اثبات و با استفاده شدن مکرر آن - توسط نویسندگان کتاب - در صنعت آزمون شده است. این کتاب تنها یک گردآوری و ساختاردهی به تمامی این الگو‌ها بوده است تا برای دیگر مهندسان حوزه‌ی شی‌گرا یک مرجع باشد.الگوی طراحی چیست؟یک الگو به معنای یک دوتاییِ مشکل-راه‌حل در یک زمینه خاص می‌باشد. هر الگو (صرف نظر از حوزه مورد بحث آن) برای یک مشکلِ تکرارشونده، یک راه‌حل با «قابلیتِ استفاده مجدد»، در یک زمینه‌ی خاص ارائه می‌دهد. زمینه می‌تواند (۱) حوزه‌ی مساله (مانند حوزه‌ی مالی، حوزه‌ی خرید)، یا (۲) پارادایم راه‌حل (مانند شی‌گرا، تابعی) را مشخص کند و یا به (۳) فعالیتی خاص (مانند آزمون، تحلیل، طراحی) اشاره داشته باشد.به این ترتیب، الگوهای طراحیِ دسته‌ی چهار نفره نیز راه‌حل‌هایی با قابلیت استفاده مجدد برای مشکلات تکرارشونده‌ی پارادیمِ شی‌گرا می‌باشند. برای شناخت بهتر از زمینه‌ی این الگو‌ها، [۱] تصریح می‌کند که الگو‌های این کتاب همگی در یک سطح انتزاع قرار گرفته‌اند؛ نه آن‌قدر سطح پایین هستند که بر فرض مثال راه‌حلی برای ایجاد داده‌ساختار‌هایی مانند «لیست پیوندی» و «جدول هش» ارائه دهند نه آنقدر سطح بالا هستند که الگوی معماری به شمار آیند. همچنین وابسته به حوزه‌ی خاصی از اپلیکیشن‌ها (مانند حوزه‌ی مالی، حسابداری، خرید و فروش و …) نبوده و برای طراحیِ «واسط کاربری» و «پایگاه داده» یا برنامه‌سازی «هم‌روند» و «توزیع‌شده» موضوعیت ندارند.این تحقیق روی چه مواردی تمرکز دارد؟در بخش «پیش‌گفتار کتابِ» [۱]، دو پیش‌نیاز از این کتاب تبیین شده است:این کتاب یک مقدمه برای تکنولوژی یا طراحیِ شی‌گرا نمی‌باشد… این کتاب فرض می‌کند بر حداقل یک «زبان شی‌گرا» به میزان معقولی مسلط هستید و همچنین در «طراحی شی‌گرا» مقداری تجربه دارید.از طرف دیگر تا لحظه نگارش این تحقیق، انشاها و مقالات بسیاری در مورد الگوهای طراحی دسته‌ی چهار نفره وجود دارند که صرف الگوها و نحوه‌ی اعمال کردن آن‌ها را در زبان‌های برنامه‌نویسی مختلف مورد بررسی قرار می‌دهند. به همین سبب، این تحقیق رویکرد متفاوتی برای بررسی این کتابِ نفیس اتخاذ می‌کند؛ در این رویکرد سعی شده است برای دومین پیش‌نیاز ذکر شده در نقل‌قول فوق، یعنی «طراحی شی‌گرا»، توضیحی ارائه شود.در این رویکرد ابتدا اصول مختلف شی‌گرا که در شکل‌گیری و اثبات کارآمدیِ الگوهای دسته‌ی چهار نفره موثر بوده‌اند، مورد بررسی قرار می‌گیرند؛ پس از آن به بررسی چند الگو از این کتاب خواهیم پرداخت و در این بررسی به اصول و الگوهایی که پیش‌تر توضیح داده‌ایم رجوع خواهیم کرد تا درک عمیق‌تری از نحوه شکل‌گیری هر الگو حاصل شود. امید است پس از مطالعه‌ی این تحقیق، قرائت کننده علاوه بر یادگیری الگو‌های توضیح داده شده، روشِ بررسی دیگر الگو‌های کتاب دسته‌ی چهار نفره را نیز با استفاده از اصول و الگو‌های شی‌گرا درک کند.بخش اول: مروری بر اصول مهندسی نرم‌افزارِ شی‌گراطراحی یک نرم‌افزار شی‌گرا سخت است، طراحی یک نرم‌افزار شی‌گرا که دارای قابلیت استفاده مجدد باشد سخت‌تر. [۱]به راستی اگر طراحی شی‌گرا سخت است چرا همچنان از برترین ترند‌های مهندسی نرم‌افزار به حساب می‌آید؟ همچنین سرمنشا این سختی کجاست و چطور می‌توان آن را مرتفع نمود؟آرزوی مهندسی نرم‌افزار را می‌توان با اصل باز-بسته (OCP) نشانه گرفت. تغییرات محصول در هر شکل از مهندسی همواره سخت است، اما تغییر در یک مهندسی که محصول نهایی آن ماهیت نرم دارد از جهات بسیاری سخت‌تر می‌باشد. همانطور که [۷] اذعان می‌دارد، یک سیستم نرم‌افزاری طی وصول تغییرات بدتر می‌شود. واژه‌ی «بدتر» مورد استفاده‌ در این تحقیق، معادل Deteriorate در [۷] می‌باشد" شایان توجه است که یکی از حوزه‌های استفاده اصلی این واژه در فضای بیمارستانی و به منظور ارجاع به بدتر و غیر قابل کنترل شدن وضعیت یک بیمار است (فرهنگ لغت کمبریج). [۷] دلیل مرگ بسیاری از اپلیکیشن‌های امروزی را «تغییر» می‌داند؛ این در حالیست که اصل دوم (از اصول دوازده‌گانه‌ی) روش‌های فراگیر چابک تشویق به پذیرش هر شکل از تغییرات است.اصل باز-بسته در واقع آرزوی غایی ایجاد نرم‌افزار است که با اصول و الگوهای دیگر پارادایم شی‌گرا محقق می‌شود. این اصل به دنبال آن است که نرم‌افزار ایجاد شده مانند یک محصول سخت‌افزاری، به راحتی گسترش یابد (باز نسبت به گسترش) بی‌آنکه ساختار داخلی آن دستخوش تغییر شود (بسته نسبت به تغییر ساختار داخلی).اما چرا طراحی شی‌گرا سخت است؟ یک پاسخ خوب از خود [۱] دریافت می‌شود:طراحان تازه‌وارد معمولا با گزینه‌های متعددی که در شی‌گرا موجود می‌بینند، سردرگم شده و مجاب به عقب‌نشینی و استفاده از روش‌های غیرشی‌گرای پیشین خود خواهند شد.جواب دیگر را در این جمله‌ی طلایی از دوره‌ی CPSC 333 دانشگاه کلگری جستجو می‌کنیم:بیشتر چیز‌هایی که راجب ایجاد نرم‌افزار می‌دانید (یک‌جورایی) غلط‌اند.به این ترتیب طراحان تازه وارد شی‌گرا به جای استفاده‌ی مجدد از تجارب محققان این زمینه، دست به آزمون و خطا در این پهنه‌ی بی انتها می‌زنند که جز سردرگرمی آن‌ها به همراه ندارد و در نهایت به بازگشتشان به همان روش‌های غیرشی‌گرا و ناکارآمد گذشته منجر خواهد شد.این تحقیق در ادامه به توضیح اصول و الگوهای اولیه‌ی این پارادایم می‌پردازد و نحوه حضور آن‌ها در الگو‌های دسته‌ی چهار نفره را تشریح می‌کند.اصول شی‌گرااصل یک‌مسئولیتی (SRP)اصل SRP از دل انسجام بیرون آمده است. همانطور که می‌‌دانید انسجام بر این مورد تاکید دارد که عملکرد و وظایفی که یک کلاس یا یک ماژول بر عهده دارد، با یکدیگر ارتباط معنایی داشته باشند و در واقع بتوان این وظایف را به عنوان یک مسئولیت (یا راستای) واحد در نظر گرفت.یک کلاس فقط و فقط باید یک دلیل برای تغییر داشته باشد. [۶]حال برای اینکه به جمله بالا دست پیدا کنیم نیاز است که هر کلاس یا ماژول فقط یک مسئولیت‌ داشته‌باشد، زیرا که هر مسئولیت می‌تواند دلیلی برای تغییر در یک راستای متفاوت باشد. پس اگر یک کلاس بیش از یک مسئولیت را به عهده بگیرد، دلایل مختلف در راستا‌های مختلف می‌توانند باعث تغییر در کلاس‌ شوند (بوی بدی که به اسم تغییرات واگرا نیز شناخته می‌شود). در ضمن این کار باعث می‌شود که مسئولیت‌ها با یکدیگر جفت شوند و تغییر در یکی منجر به ناکارامدی مسئولیت دیگر و بروز خطا در برخی از قسمت‌ها شود که ما را منجر به تغییر مسئولیت‌های دیگر کلاس نیز می‌کند.حال می‌خواهیم به معنای مسئولیت بپردازیم.مسئولیت به نوعی تعریف می‌شود که یک دلیل برای تغییر باشد. [۶]اگر در هنگام تعریف یک کلاس، بیش از یک انگیزه برای تغییر در آن را متصور شوید، آن کلاس در واقع بیشتر از یک مسئولیت را بر عهده دارد. این تشخیص گاهی اوقات سخت به نظر می‌رسد زیرا اکثر ما مسئولیت‌ها را در یک گروه می‌بینیم و نمی‌توانیم از هم تفکیک کنیم.گاهی اوقات می‌توان برای یک کلاس جنبه‌های مختلفی از تغییر را متصور شد که این تغییرات هیچ‌گاه اتفاق نمی‌افتند، پس در این شرایط نیاز به شکستن کلاس به طوری که هر زیرکلاس حاصل، تنها یک راستای تغییر را عهده دار شوند، نداریم. زیرا این کار باعث پیچیدگی بیشتر کد می‌شود و خوانایی و نگهداری آن را سخت‌تر می‌کند.در نهایت باید بگوییم که این اصل ساده‌ترین اصل مهندسی نرم‌افزار است که در عین حال دستیابی به یک نسخه درستی از آن بسیار سخت است. یکی کردن مسئولیت‌ها کاری است که بسیاری از ما به صورت طبیعی و ناخواسته انجام می‌دهیم. شکستن این نوع تعاریف به مسئولیت‌های مجزا در واقع هدفیست که مهندسی نرم‌افزار در ذات خود دنبال می‌کند به طوری که بقیه اصول نیز به هر حال از طریقی به این اصل باز می‌گردند.اصل جایگزینی لیسکوف (LSP)طبق کتاب [۶]، می‌توان اصل جایگزینی را به این صورت تعریف کرد:زیر‌نوع‌ها باید بتوانند با نوع‌های پدر (نوع‌های پایه) جایگزین شوند.اگر بخواهیم به صورت شفاف‌تری این تعریف را بیان کنیم،‌ می‌توانیم دو کلاس فرزند و پدر را در نظر بگیریم. فرض کنید که در قسمتی از پایگاه کد از یک کلاس انتزاعی به عنوان یک واسط استفاده میکنیم. در این مورد اگر کلاس‌های فرزند طوری پیاده‌سازی شده باشند که اصل جایگزینی را نقض کنند، در ارتباط کارخواهانِ این کلاس پدر، به مشکل بر خواهیم خورد؛ زیرا خدماتی که پیاده‌سازی‌های فرزند ارائه می‌‌دهند با قراردادی که کلاس پدر تضمین کرده است، تفاوت دارد و این تفاوت منجر به خطا و حالت‌های پیش‌بینی نشده در سمت کارخواهان خواهد شد.این اصل به نوعی OCP را نیز برایمان فراهم می‌کند. زیرا اگر این اصل را در پیاده‌سازی‌ کلاس‌های فرزند در نظر بگیریم، به راحتی می‌توانیم با افزودن کلاس‌های فرزند، پیاده‌سازی‌‌های مختلفی را برای کاربران ارائه دهیم به طوری که هیچ کدام از کارخواهان از جزییات پیاده‌سازی اطلاع نداشته‌نباشند (به شرطی که با استفاده از اصل وارونگی وابستگی دید از سمت کارخواهان به سمت کلاس پدر باشد، نه فرزند).دو موردی که باید برای رعایت این اصل به آن توجه کنیم:کلاس فرزند نباید پیش‌شرط‌های قوی‌تری نسبت به کلاس پدر داشته باشند.کلاس فرزند نباید پس‌شرط‌های ضعیف‌تری نسبت به کلاس پدر داشته باشند.اگر این دو مورد نقض نشود، اصل جایگزینی برقرار است.اصل وارونگی وابستگی (DIP)به طور خلاصه، اصل وارونگی وابستگی را می‌توان در دو نکته زیر دید که در کتاب [۶] مطرح شده‌است:ماژول‌های سطح بالا نباید به ماژول‌های سطح پایین وابسته باشند، بلکه هر دو باید به انتزاعات وابسته باشند.انتزاعات نباید به جزییات وابسته باشند، بلکه جزییات باید به انتزاعات وابسته باشند.برای اینکه بتوانیم اصل وارونگی وابستگی را رعایت کنیم، باید در میان تمامی ارتباطات بین کلاس‌های عینی از کلاس‌های انتزاعی و یا واسط استفاده کنیم و به زبانی دیگر هیچ دو کلاس عینی نباید به صورت مستقیم با یکدیگر ارتباط داشته باشند، بلکه باید از طریق یک واسط یا یک کلاس انتزاعی از یکدیگر خدمات بگیرند و با یکدیگر همکاری داشته باشند. (تبلور این اصل در الگوی «غیرمستقیم‌سازی» از GRASP نیز مشهود است).در نهایت اگر از این اصل به درستی استفاده کنیم، علاوه بر اینکه خوانایی کد بالا می‌رود و ساختار قابل فهم‌تر در طراحی حاصل می‌کند، در نگهداری نرم‌افزار نیز تاثیری به سزایی دارد به طوری که تغییرات مورد نیاز را می‌توان بدون انتشار به باقی بخش‌ها، اعمال کنیم؛ چرا که کلاس‌های انتزاعی و واسط‌ها به صورت یک بخش ایزوله در‌آمده‌اند که بقیه کلاس‌ها هیچ دیدی به پیاده‌سازی آن‌ها ندارند و وابستگی بی‌مورد به کلاس‌های عینی ایجاد نشده‌است.این اصل در اکثریت الگوهای دسته‌چهار نفره (مانند الگوی حالت، راهبرد، پل و …) بروز یافته است.اصل جداسازی واسط (ISP)بسیار رخ داده است که واسط‌هایی تعریف شده در سیستم، حجیم هستند و ذیل این واسط‌ها یک مجموعه از وظایفی تعریف شده است که عموما منسجم نیستند. این اصل تاکیدش بر این است که باید این واسط‌ها شناسایی شوند و به واسط‌های ریزتر با مجموعه وظایفی منسجم شکسته شوند. در این صورت هر یک از این ریز واسط‌ها می‌توانند به گروه‌ خاصی از کاربران سرویس دهند و نیاز به تجمیع با دیگر واسط‌ها ندارند، زیرا کاربران نباید به صورت اجباری به متد‌هایی که نیاز ندارند، وابستگی پیدا کنند [۶].وابستگی کاربران مختلف به یکدیگر از طریق یک واسط مشترک می‌تواند منجر به تغییرات نا‌‌خواسته در قسمت‌هایی شود که هیچ ارتباط معنایی با تغییر ظهور کرده ندارند. به عبارتی بابت وابستگی بی‌مورد آن‌ها به یکدیگر، بعضا مجبور به تغییر قسمت‌های نامرتبط می‌شویم که به اصطلاح می‌گوییم بوی بدِ تغییرات منتشر شونده رخ داده است.برداشت دیگری که کتاب [۶] از این اصل ارائه داده است:‌اگر کاربران را جداسازی کرده‌ایم، باید واسط‌هایی که دسته‌‌های مختلف کاربران از آن استفاده می‌کنند را نیز جداسازی کنیم، زیرا کاربران قدرت خود را روی واسط‌ها اعمال می‌کنند و روی آن‌ها تاثیر می‌گذارند.[۶] برای حل این مشکل دو راه حل ارائه داده است که یکی مربوط به پیاده‌سازی با استفاده از وراثت چندگانه و دیگری از طریق واگذاری می‌باشد.جداسازی با استفاده از وراثت چند‌گانه به این صورت است که در لایه ابتدایی، واسط‌های جدا از هم تعریف می‌کنیم و در صورتی که نیاز به پیاده‌سازی چند واسط داشتیم، باید از همه واسط‌های مورد نیاز ارث‌بری کنیم.جداسازی با استفاده از واگذاری نیز به این صورت است که اگر نیاز به یک واسط داشته‌باشیم، می‌توانیم کار مورد نیاز را به یک شی بدهیم که آن واسط را پیاده‌سازی کرده است و پاسخ را از آن شی دریافت کنیم و خروجی دهیم. توجه داشته باشید که فرق این روش با روش جداسازی قبلی، استفاده از ارتباط انجمنی به‌ جای وراثت بین کلاس‌ها است که انعطاف پذیری بیشتری دارد (چرا که در «زمان‌اجرا» قابل افزایش، کاهش و تغییر است).اصل حداقلِ دانش (PLK)رهنمون این اصل اولین بار توسط ایان هالند از دانشگاه نورث‌ایسترن در انتهای سال ۱۹۸۷ ارائه شد و سال بعد به همراه همکارانش در [۵] تجمیع شد. به صورت خلاصه تعریفی که [۵] برای این اصل ارائه داده است به این صورت است:به ازای هر کلاس C که متد M به آن پیوست شده است، متد M فقط می‌تواند به اشیایی پیام ارسال کند که نمونه‌ای از کلاسی باشد که یکی از ویژگی‌های زیر را داشته باشد:آرگومان‌های متد M (شامل خود C).نمونه‌هایی که در متغیر‌های کلاس C هستند.آرگومان‌های متد M نیز شامل اشیایی می‌شوند که خود M آن‌ها را به صورت مستقیم یا با صدا زدن توابع ساخته است یا متغیر‌هایی که به صورت گلوبال تعریف شده‌اند.این اصل دو هدف مهم را دنبال می‌کند. اولین هدف مربوط به سادگی تغییرات است به این مفهوم که اگر برنامه نیاز به تغییر داشت، با نهایت سادگی بتوان‌ آن‌ها را اعمال کرد. دومین هدف نیز مربوط به ساده کردن و کاهش پیچیدگی توابع و پیاده‌سازی است به طوری که با کم کردن دانش مورد نیاز برای هر قسمت، از پیچیدگی و حجیم شدن توابع جلوگیری می‌کند. [۵]و در نهایت باید اشاره کنیم به موردی که که در [۵] نیز آورده شده است:اگر این اصل را به همراه سه محدودیت «۱. کمینه کردن کد تکراری ۲. کمینه کردن تعداد آرگومان‌های توابع ۳. کمینه کردن تعداد متدهای هر کلاس » روی نرم‌افزار در نظر بگیریم، منجر به ایجاد یک سبک برنامه‌نویسی خوب و درست می‌شود.اصل استفاده مجددِ مرکب (CRP)دو راه استفاده مجدد در شی‌گرا، وراثت و ترکیب هستند که وراثت همانطور که می‌دانید کلاس فرزند با بهره‌گیری از کلاس پدر، می‌تواند از ویژگی‌های کلاس پدر و پیاده‌سازی‌های آن استفاده کند. راه دیگر استفاده مجدد ترکیب اشیا با یکدیگر و ایجاد یک واسط برای این ترکیب است به طوری که با استفاده از واگذاری می‌توان از ویژگی‌هایی که این شی مرکب در اختیار می‌گذارد، بهره برد بدون آنکه اطلاعی از ساختار درونی این شی مرکب داشت. این طراحی به جعبه سیاه نیز معروف است [۱].همانطور که مشخص است، استفاده مجدد وراثت در لایه کلاس است و استفاده مجدد ترکیب در لایه شی است. به وضوح بهره‌گیری از ترکیب بسیار انعطاف‌پذیرتر از وراثت است چرا که در زمان‌اجرا می‌توان در آن تغییرات ایجاد کرد و در نهایت کار‌های پیچیده‌تری را با آن پیش برد.همانطور که در صفحه ۳۵ کتاب [۱] هم آورده شده، دیگر مزیت استفاده از استفاده مجدد مرکب این است که در زمان اجرا می‌توان ارتباطات بین این اشیا را تغییر داد و ساختار‌های دیگری را در نرم‌افزار ایجاد کرد، در حالی که استفاده از ساختار‌های موروثی در زمان کامپایل فیکس می‌شوند و دیگر نمی‌توان آن‌ها را تغییر داد.اصل باز-بسته (OCP)همه نرم‌افزار‌‌ها در دوران حیات خود دچار تغییر خواهند شد و باید از ابتدای تولید نرم‌افزار به این بیاندیشیم که نرم‌افزار ایجاد شده باید بتواند بیشتر از نسخه اولیه دوام بیاورد. اصل OCP به راه‌ کارهایی برای توسعه چنین نرم‌افزاری می‌پردازد.تمامی موجودیت‌های نرم‌افزار (کلاس‌ها، ماژول‌ها، توابع و …) باید پذیرا (نسبت به توسعه‌ی خدماتشان) و بسته (نسبت به تغییر ساختار داخلی‌شان) باشند. [۶]هنگامی که تغییری در یک برنامه ایجاد می‌شود، نباید این تغییر به صورت منتشرشونده به بقیه ماژول‌های وابسته نیز انتشار یابد. اصل OCP توصیه می‌کند که برنامه به نحوی بازآرایی شود که در صورت مواجه شدن با چنین تغییراتی، مجبور به تغییر ماژول‌های مرتبط نباشید. اگر این اصل به درستی اجرا شود، تغییرات در برنامه فقط منجر به افزودن کد‌های جدید می‌شوند و نیاز به تغییر در قسمت‌‌هایی از برنامه که تا به حال به درستی کار می‌کردند، نمی‌باشد. کلید اصلی در دستیابی به این اصل، استفاده از انتزاع (به خصوص اصل وارونگی وابستگی) است که در بسیاری از زبان‌ها می‌توان از این قابلیت استفاده کرد.در نهایت باید متوجه این موضوع بود که اصل OCP در دل طراحی شی‌گرا جای دارد و توسعه سیستم‌هایی که از این اصل پشتیبانی می‌کنند، باعث ایجاد خاصیت‌هایی نظیر استفاده مجدد، انعطاف‌پذیری و قابلیت نگهداری در سیستم نرم‌افزاری می‌شود. البته باید متذکر شویم که دستیابی به این اصل به مراتب سخت‌تر از توضیح آن است و تنها استفاده از یک زبان شی‌گرا و بهره‌گیری از انتزاع در جای جای برنامه، این اصل را تضمین نمی‌کند.الگو‌های نرم‌افزاری عمومی تخصیص مسئولیت (GRASP)الگو‌های نرم‌افزاری عمومیِ تخصیص مسئولیت (به اختصار GRASP) مجموعه‌ای از ۹ الگوی ریزدانه‌ی شی‌گرا است که توسط کِرِگ لارمن در [۴] معرفی شده است. در الگوهای طراحی شی‌گرا، مانند الگو‌های GoF، معمولا یک یا چند الگوی GRASP مانند یک نقشه‌ی راه مستتر می‌باشند و دو الگوی «اتصال کم» و «انسجام زیاد» از آنها امروزه ستاره شمالی بسیاری از ابعاد مهندسی نرم‌افزار هستند.وقتی صحبت از مسئولیت در اصل یک‌مسئولیتی به میان آمد، در واقع مقصود و راستای تغییراتِ یک کلاس مد نظر بوده است. مسئولیت در این زمینه، و غالبِ زمینه‌های دیگر شی‌گرا، به مجموعه‌ی منسجمی از «داده» و «رفتار» موجود در کلاس اشاره می‌کند که مابه‌ازای پیاده‌سازی آن‌ها مجموعه‌ای از «صفت‌ها» و «متد‌های» به هم مرتبط خواهند بود.این واژه مشابه مفهومی از مسئولیت است که کِنت بِک در کارت‌های CRC معرفی می‌کند. به این ترتیب هر کلاس دارای یک مجموعه کوچکی از مسئولیت‌ها (حداکثر چهار یا پنج مورد) خواهد بود که امیدوارانه همگی آن‌ها در یک راستای تغییر قرار می‌گیرند (تا اصلِ SRP نیز برقرار باشد).در ادامه به طور خلاصه هر یک از این الگو‌ها را با یکدیگر بررسی می‌کنیم.۱. متخصص اطلاعاتاین مورد الگوی عمومی کل مبحث تخصیص مسئولیت می‌باشد. این الگو بیان می‌کند که از بین گزینه‌های برآورده کردن یک مسئولیت، باید کلاسی انتخاب شود که داده لازم برای انجام آن مسئولیت را دارا است. این الگو از ستون «کپسوله‌سازی» مترتب شده است، که اشاره می‌کند اشیا در واقع کپسول‌های داده-رفتار می‌باشند و از همین رو کپسولی برای پیاده سازی رفتار لازمِ یک مسئولیت انتخاب خواهد شد که در ابتدا داده‌ی مورد نیاز آن رفتار را دارا باشد.این الگو خط‌بنای الگوهای دیگر GRASP خواهد بود و به انسجام هر چه بیشتر کلاس‌ها منجر می‌شود.۲. سازندهدر طراحی شی‌گرا «شی‌گیری» از کلاس‌های مختلف همواره یک معضل است. الگوی سازنده مساله‌ی انتخاب مکان مناسب برای شی‌گیری از یک کلاس را حل می‌کند. این الگو بیان می‌دارد که برای شی‌گیری از کلاسِ A، از بین تمام اشیای موجود در قلمروی کنونی سیستم، آن شی از کلاس B مناسب این وظیفه است که یکی از معناهای مقابل در مورد آن برقرار باشد: (۱) B با A رابطه ترکیبدارد. (۲) B با A رابطه تجمیع دارد. (۳) B اشیای A را ثبت و ضبط می‌کند (معمولا یک رابطه‌ی انجمنی در این موارد مطرح است). (۴) B وابستگی‌ از نوع «استفاده» با A دارد. در نهایت (۵) B ارتباطی با A ندارد ولی داده مورد نیاز برای شی‌گیری از A را دارا است.برای تمام B های مختلفی که یکی از پنج معنای فوق را دارا هستند اولویت با آن کلاسی است که معنای با شماره کمتر را دارد.استفاده از این الگوی GRASP در کنار الگوهای «متدِ کارخانه» و «کارخانه‌ی انتزاعی» از دسته‌ی چهار نفره یک باید است، تا فرایند ایجاد و مقداردهی اولیه اشیا - که در یک سیستم شی‌گرا بسیار تکرارشونده است - به بالا رفتن اتصالاتِ زائد و کاهش انسجامِ کلاس‌های سازنده منجر نشود.۳ و ۴. اتصال کم و انسجام زیادامروزه کم کردن اتصالات بین کلاس‌ها و ماژول‌ها و زیاد‌کردن انسجام هر ماژول، طرز فکر کل مهندسی نرم‌افزار شده است. اگرچه اصول دیگر GRASP همگی در راستای کم‌کردن اتصالات بین کلاس‌ها و بالا‌بردن انسجام درون آن‌ها می‌باشند، لارمن این دو اصل را به عنوان دو الگوی مستقل برای تخصیص مسئولیت به کلاس‌ها معرفی می‌کند تا سهل انگاشته نشوند.۵. کنترل‌کنندهبرای وظیفه‌ی کلید‌زدن وقایع و کار‌ها، و همچنین کارچرخانی بین اجزای یک ماژول، می‌توان نقطه‌های مختلف ماژول کارگزار را از نقاط مختلف ماژول کارخواه فراخوانی کرد، که اتصالات بین دو ماژول را بسیار زیاد می‌کند (و بسیار نامطلوب است).راه‌حل جایگزین این است که ماژول کارخواه وظیفه‌ی خود را از یک شیِ جعلی - که لارمن آن را کنترل‌کننده می‌نامد - درخواست کند. آن شی جعلی نیز بجای انجام آن کار، تنها درخواست را به بخش‌های مختلف ماژول کارگزار را هدایت کند؛ سپس با استفاده از پاسخ‌های دریافتی از کارگزار، پاسخ مورد انتظارِ ماژول کارخواه را شکل داده و بازگرداند.به این شکل، یک غیرمستقیم‌سازی بین کارخواه و کارگزار نیز، تعبیه می‌شود که به بهبود (کاهش) اتصالات می‌انجامد.تبلور این الگوی GRASP را در الگوهای «نما» و «میانجی» از کتاب دسته‌ی چهار نفره مشاهده می‌کنیم، که اشیای نما تنها کارچرخانی در یک ماژولِ پیچیده را بر عهده می‌گیرند و اولویت‌شان کاهش اتصالاتِ درون سیستم است.۶. چندریختیپیش‌تر در اصل LSP اشاره کردیم که هرگونه استفاده از توارث در مواردی که جایگزینی کلاس مادر و فرزند از لحاظ معنایی برقرار نیست و توارث صرفا به منظور استفاده مجدد شکل گرفته است، دارای ایراد است. همچنین در اصل CRP مطرح کردیم که به دلیل بالا بودن اتصال در یک ساختار توارثی و رخ دادن «مشکل کلاس پایه‌ی شکننده» همواره استفاده از واگذاری به جای توارث رجحان دارد. تنها یک مورد کاربرد بسیار ارزشمند برای ساختارهای توارثی مطرح خواهد بود و آن چندریختی‌ای است که در کنار کپسوله‌سازی و توارث، سه ستون شی‌گرا را شکل می‌دهند.اگرچه این ستونِ شی‌گرایی، مهندسان تازه‌کار این حوزه را یاد چندریختی انواع در زبان‌های «بررسی نوعِ ایستا» (مانند جاوا) می‌اندازد، مقصود اصلی لارمن از این الگو، استفاده از این ستون در ساختارهای توارثی (دارای قابلیت جایگزینی ذاتی) به منظور ایجادِ چندریختی در رفتار است.تبلور چندریختی در رفتار را در الگوی «بازدیدکننده» - که هر بازدیدکننده طبق حوزه‌ی تخصص خود هر کلاسِ المان را بازدید می‌کند - یا الگوی «کارخانه‌ی انتزاعی» - که هر کارخانه‌ی وابسته به خانواده‌ی محصولات مربوط به خودش، محصول مورد نظر را تولید می‌کند - مشاهده می‌کنیم. البته استفاده از چندریختی تنها منحصر به همین دو الگوی دسته چهار نفره نمی‌باشد، چرا که خبرگان حوزه‌ی شی‌گرا چندریختیِ رفتار را در تمامی ساختارهای توارثی طراحی خود مستتر می‌سازند.۷. غیرمستقیم سازیتغییرات پیش از شی‌گرایی عمدتا واگرا بودند. تغییرات در یک ماژول به دلیل انسجام کم و اتصالات زیاد آن به ماژول‌های دیگر، مرتبا به بخش‌های دیگر کد منتشر می‌شد. یک الگوی خوب برای سد سازی مقابل این انتشار تغییرات، غیرمستقیم ساختن ارتباطات است. به این شکل امیدواریم تغییراتی که در حال انتشار هستند، در کلاس‌هایی که تنها به منظور غیرمستقیم سازیِ ارتباط قرار داده‌ایم، متوقف شوند و به ماژول‌های وابسته (غالبا کارخواه) راه نیابند.اساسا تمامی اشیای «بسته‌بندی کننده» (شامل چهار الگوی آداپتور، دکوراتور، نما و پروکسی) دو الگوی «غیرمستقیم سازی» و «جعل خالص» را برقرار می‌کنند. همچنین در الگوهای دیگر دسته‌ی چهار نفره مانند میانجی و تکرارگر نیز، یک نوع از چنین غیرمستقیم سازی‌ای در نظر گرفته شده است. به طور کل استفاده از هر الگوی دسته‌ی چهار نفره که این الگوی GRASP را برقرار کرده است× به کاهش چشمگیر اتصالات درون سیستم منجر می‌شود.۸. جعلِ خالصاولین تفاوتِ کلاس‌های قلمروی طراحی با کلاس‌های قلمروی تحلیل، وجود کلاس‌های جعلی (تصنعی) در قلمروی جواب است که مابه‌ازایی در جهان واقع و فضای مسئله ندارند. یکی از مهمترین مشخصه‌های یک طراحی ناشیانه‌ی شی‌گرا وجود تنها کلاس‌های قلمروی مسئله در طراحی است (کلاس‌هایی که مابه‌ازاهایی در جهان واقع دارند) که اشیای گرفته شده از آن‌ها تمام وظایف و مسئولیت‌های سیستم نرم‌افزاری را محقق می‌سازند.در مقابل، یک طراحی شی‌گرای ورزیده شامل تعداد زیادی کلاس‌های جعلی و در عین حال منسجم است که مسئولیت‌های مختلف را انجام می‌دهند و ارتباطات میان این کلاس‌ها تنها از طریق واسط‌ها، (به منظور حفظِ DIP، با حداقل اتصال) که خود ماهیت‌های تصنعی هستند، برقرار می‌شوند.با نگاه به الگوهای دسته‌های چهار نفره در می‌یابیم که در بسیاری از آن‌ها نیز چنین کلاس‌های تصنعی به تعداد قابل توجهی وجود دارند که به «سست اتصال بودن» الگوها کمک شایانی کرده است.۹. تغییراتِ محافظت شدهدر مهندسی نرم‌افزار امروز که اکثر شرکت‌ها فرایند‌های چابک ایجاد نرم‌افزار (علی‌الخصوص) اقتباس می‌کنند، مدیریت تغییرات یک مساله حیاتی است. یک مدیریت نادرست بلافاصله به مرگ یک نرم‌افزار یا حداقل بخشی از کد آن منجر می‌شود که دوباره‌کاری آزاردهنده‌ای به همراه دارد.این الگو بیان می‌دارد که برای بخش‌هایی از نرم‌افزار که میخواهیم قسمت‌های دیگر نرم‌افزار را از تغییرات آن در امان نگه داریم، باید توسط یک کلاس بسته‌بندی شوند تا تغییرات داخلی آن‌ها به بیرون منتشر نشود و یا تغییرات بیرونی به داخل آن‌ها نرسد. این حجم از مقاومت در برابر انتشار تغییر برای یک زیرسیستم، می‌تواند ناشی از (۱) شفاف و نهایی نبودن نیازمندی‌ها در مورد آن زیرسیستم یا (۲) قدیمی و «موروثی» بودن آن زیرسیستم (بالطبع کوچکترین تغییرات در آن بسیار سخت است) باشد.بخش دوم: الگوهای دسته‌ی چهار نفرهالگوهای دسته‌ی چهار نفره الگوهایی هستند که برای طراحی استفاده می‌شوند. این الگوها تمرکزشان عموما بر انعطاف‌پذیری است تا شاخص‌های دیگر طراحی، مثل استفاده‌ی مجدد. از این جهت، تمرکزشان بیشتر بر کم‌کردن جفت‌شدگی است و ممکن است در بعضی مواقع به انسجام هم ضربه بزنند. این مجموعه الگو براساس سه اصل استفاده‌ی مجدد مرکب، وارونگی وابستگی و تغییرات محافظت شده ساخته شده است.این مجموعه الگوهای طراحی به سه دسته‌ی تکوینی، ساختاری و رفتاری تقسیم می‌شود. دسته‌ی تکوینی شامل الگوهایی‌ست که برای ساخت اشیاء استفاده می‌شود. دسته‌ی ساختاری شامل الگوهایی‌ست که بیشتر در ساختار و محدوده‌ی کلی اتصال اشیاء به هم نمود دارد. دسته‌ی رفتاری شامل الگوهایی‌ست که بیشتر در رفتار اشیاء در هنگام اجرا نمود دارد. ناگفته نماند مرز بین دو بخش ساختاری و رفتاری مبرز نیستند و جامعه‌ای از مهندسین نرم‌افزار به عدم وجود مرز بین این دو دسته باور دارند.در ادامه یک مجموعه‌ی کوچکی از الگوهای دسته‌ی چهارنفره را تعریف و تحلیل می‌کنیم تا یک دید کلی از موارد استفاده‌ی این الگوها را به شما ارائه دهیم. برای بدست‌آوردن دید بهتر از این الگوها، به‌ازای هرکدام از سه‌دسته یک مثال نسبتا پراستفاده و پیچیده ارائه می‌دهیم.مثال ۱ از الگوهای ایجادی: الگوی سازندهمشکلمی‌خواهیم الگوریتم ساخت یک شیء پیچیده را از ساختار شیء و چگونگی قرار گرفتن قسمت‌های آن مستقل کنیم، به طوری که یک الگوریتم ساخت برای ساخت چند شیء پیچیده مورد استفاده قرار گیرد. همچنین استفاده از این الگو باعث می‌شود بتوانیم چند الگوریتم برای ساخت اشیاء پیچیده ارائه دهیم.راه‌حلشکل ۱. نمودار کلاس الگوی سازندهدر این نمودار یک کلاس Director داریم که الگوریتم ساخت شیء پیچیده در تابع construct() آن توصیف می‌شود. کلاس Director با کلاس Builder دارای رابطه‌ی تجمیع است. کلاس Builder یک کلاس انتزاعی است که تابع‌های مربوط به قرارگیری اشیاء درحال ساخت، در کلاس‌های پسر آن باید پیاده‌سازی شود. حال، به‌ازای هر شیء به‌خصوص می‌توانیم یک Builder عینی بسازیم که قسمت‌های آن شیء به‌خصوص را به‌هم وصل می‌کند. در این نمودار ConcreteBuilder را برای ساخت شیء Product تعریف کرده‌ایم.از آنجا که کلاس Director فقط به کلاس Builder دسترسی دارد، نیاز است Builder عینی مورد استفاده، توسط یک شخص ثالث، که عموما می‌تواند مشتری‌ای باشد که از شیء به‌خصوص می‌خواهد استفاده کند، مشخص شود. در نتیجه، این الگو از نوع محدوده‌شیء است.عواقباز آنجا که در این الگو مسئولیت بهم وصل کردن قسمت‌های شیء از الگوریتم ساخت شیء جدا شده و به کلاس Builderواگذاری شده‌است، باعث افزایش انسجام کلاس‌ها می‌شود و به پیروی بیشتر از اصل یک‌مسئولیتی کمک شایانی می‌کند.با توجه به نمودار کلاسی الگو، نقضی از اصل جایگزینی لیسکوف دیده نمی‌شود و تمام کلاس‌های پسر عملیات‌های ذکر شده در کلاس‌های پدر را پیاده‌سازی می‌کنند و همینطور قاعده‌ی «بیشتر انتظار نداشته‌باش و کمتر ارائه نده» برقرار است.کلاس Director فقط به کلاس Builder وابسته است. در نتیجه، هیچ وابستگی مستقیم به کلاس‌های عینی دیده نمی‌شود و اصل وارونگی وابستگی برقرار است.می‌توان گفت به غیر از یک قسمت، در قسمت‌های دیگر اصل جداسازی واسط برقرار است. استفاده‌‌کننده‌ی بیرونی این سیستم با Builder‌های عینی کار می‌کند. در نتیجه، به تابع buildPart() آن‌ها دسترسی دارد. در صورتی که مشتری برای انجام کار خود فقط به تابع getResult() این کلاس نیاز دارد و فقط Director است که به تابع buildPart() برای انجام کار خود نیاز دارد.از آنجا که در این الگو اصل وارونگی وابستگی کاملا برقرار است و کلاس‌های استفاده‌کننده فقط به واسط مورد استفاده‌شان از کلاس‌های عینی دسترسی دارند، اصل حداقل دانش برقرار است.از آنجا که در کلاس‌های از نوع Director ساخت و وصل کردن قسمت‌های مختلف شیء را به کلاس‌های از نوع Builder واگذار کرده‌ایم، اصل استفاده مجدد مرکب برقرار است.از آنجا که در این الگو اصل وارونگی وابستگی برقرار است، برای اضافه کردن یک Builder عینی و یک نوع شیء جدید پیچیده، فقط لازم است این دو ماهیت را اضافه کنیم و نیازی به تغییر قسمت‌های دیگر نیست. همچنین برای اضافه کردن یک Director جدید هم نیازی به تغییر قسمت‌های دیگر نیست. در نتیجه، اصل باز-بسته برقرار است.در این الگو، به علت رعایت اصول اصل یک‌مسئولیتی، وارونگی وابستگی، جایگزینی لیسکوف، و حداقل دانش، از بین الگوهای GRASP الگوهای اتصال کم و انسجام زیاد، غیرمستقیم‌سازی، چندریختی و متخصص اطلاعات نمود دارند.ارتباط با دیگر الگو‌های GoFکارخانه انتزاعی: این الگو هم مثل الگوی سازنده برای ساخت اشیاء پیچیده استفاده می‌شود. فقط این دو الگو بر چیزهای متفاوت تاکید می‌کنند. کارخانه انتزاعی برای ساخت خانواده‌ای از اشیاء استفاده می‌شود و بعد از فراخوانی تابع درجا شیء مورد نظر را خروجی می‌دهد. در صورتی که، سازنده برای ساخت اشیاء با الگوریتم ساخت یکسان استفاده می‌شود، و درجا شیء مورد نظر را خروجی نمی‌دهد.مرکب: عموما الگوی سازنده برای ساخت اشیاء از نوع نمایان شده در الگوی مرکب استفاده می‌شود.مثال ۲ از الگوهای ساختاری: الگوی پلمشکلاستفاده از این الگو در مواقعی به‌کار می‌رود که می‌خواهیم انتزاع و پیاده‌سازی را از هم جدا کنیم. در این مسئله، مفاهیم انتزاع و پیاده‌سازی از تعریف کلی انتزاع و پیاده‌سازی جدا است. انتزاع در اینجا به معنای کارهایی‌ست که در مسئله‌ همیشه انجام می‌شود. قسمت‌های پیاده‌سازی هم به محیط خاص راه‌حل مسئله وابسته است. برای مثال، فرض کنید برای کشیدن یک مستطیل همیشه لازم است چهار خط رسم کنیم. رسم چهار خط یک انتزاع است، اما چگونگی رسم هر خط بستگی به محیط راه‌حل دارد و درنتیجه یک پیاده‌سازی به‌شمار می‌رود.راه‌حلشکل ۲. نمودار کلاس الگوی پلبا توجه به این نمودار، یک کلاس انتزاعی به نام Abstraction تعریف کردیم که مشتری فقط به آن دسترسی دارد. این کلاس انتزاعی از یک کلاس انتزاعی دیگر از نوع Implementor استفاده می‌کند تا کار خود را انجام دهد. حال، کلاس‌هایی که Abstraction را تدقیق کرده‌اند و به آن شکل داده‌اند را پسر Abstraction و کلاس‌های مربوط به پیاده‌سازی‌های مختلف را پسر Implementor تعریف می‌کنیم.در این راه حل، مشتری فقط به کلاس Abstraction وابستگی دارد و کلاس عینی Abstraction و همینطور Implementor عینی مورد استفاده‌ی آن توسط یک شخص ثالث،‌ که عموما پیکربند سیستم هست و به همه چیز دسترسی دارد، مشخص می‌شود. در نتیجه، می‌توان گفت این الگو از نوع محدوده‌شیء است.عواقباز آنجا که در این الگو مسئولیت پیاده‌سازی از کلاس انتزاع جدا شده و به کلاس Implementor واگذاری می‌شود، باعث افزایش انسجام کلاس Abstraction می‌شود و به پیروی بیشتر از اصل یک‌مسئولیتی کمک شایانی می‌کند.باتوجه به نمودار کلاسی الگو، نقضی از اصل جایگزینی لیسکوف دیده نمی‌شود و تمام کلاس‌های پسر عملیات‌های ذکر شده در کلاس‌های پدر را پیاده‌سازی می‌کنند و همینطور قاعده‌ی «بیشتر انتظار نداشته‌باش و کمتر ارائه نده» برقرار است.مشتری فقط به کلاس انتزاعی Abstraction وابسته است و کلاس Abstraction هم فقط به کلاس انتزاعی Implementor وابسته است. از این دو وابستگی، هیچ وابستگی مستقیم به کلاس‌های عینی دیده نمی‌شود. در نتیجه،‌ اصل وارونگی وابستگی برقرار است.از آنجا که در این مسئله یک نوع مشتری بیشتر نداریم، اصل جداسازی واسط در این الگو آن‌چنان موضوعیت ندارد.از آنجا که در این الگو اصل وارونگی وابستگی کاملا برقرار است و کلاس‌ها به کلاس‌های عینی و محتویات داخل آن‌ها دسترسی ندارند، اصل حداقل دانش برقرار است.از آنجا که در کلاس‌های از نوع Abstraction یک‌سری از عملیات را به کلاس‌های از نوع Implementor واگذار کرده‌ایم، اصل استفاده مجدد مرکب برقرار است.از آنجا که به طور کامل اصل وارونگی وابستگی برقرار است، اگر در هر قسمت از الگو، برای مثال کلاس Abstraction یا Implementor، بخواهیم یک کلاس جدید از این نوع اضافه کنیم، نیازی نیست هیچ تغییری در قسمت‌های دیگر انجام دهیم. در نتیجه اصل باز-بسته برقرار است. لازم به ذکر است در این مسئله، اگر از این الگو استفاده نمی‌کردیم، ساختار توارثی عمیق و دارای اتصال زیاد بوجود می‌آمد که اصل باز-بسته را به طور کامل نقض می‌کرد. برای مثال، برای اضافه کردن یک نوع جدید Implementor نیاز بود به‌ازای ترکیب این نوع با هر نوع از Abstraction یک کلاس جدید معرفی می‌کردیم.در این الگو، به علت رعایت اصول اصل یک‌مسئولیتی، وارونگی وابستگی، جایگزینی لیسکوف، و حداقل دانش، از بین الگوهای GRASP الگوهای اتصال کم و انسجام زیاد، غیرمستقیم‌سازی، چندریختی و متخصص اطلاعات نمود دارند.ارتباط با دیگر الگو‌های GoFکارخانه انتزاعی: می‌توان از این الگو برای ساخت و پیکربندی الگوی پل استفاده کرد.آداپتور: از الگوی آداپتور برای کار کردن کلاس‌هایی استفاده می‌شود که بهم مربوط نبوده‌اند. نیاز به چنین ویژگی عموما بعد از طراحی سیستم پیدا می‌شود. اگرچه الگوی پل عموما هنگام طراحی سیستم و برای تغییر مستقل دو بخش از سیستم انجام می‌شود.مثال ۳ از الگوهای ساختاری: الگوی بازدیدکنندهمشکلفرض کنید یک سری از عملیات به خصوص یک کلاس را می‌خواهیم از خود کلاس جدا کنیم. این کار عموما برای افزایش انسجام کلاس انجام می‌شود.راه‌حلشکل ۳. نمودار کلاس الگوی بازدید کنندهدر این نمودار کلاس‌هایی که می‌خواهیم عملیاتشان را جدا کنیم، از کلاس Element ارث‌بری می‌کنند. هر کدام از این کلاس‌های پسر دارای یک تابع accept در درون خود هستند، که در آن ذکر می‌کنند چه تابعی از کلاس Visitor را باید صدا بزنند.از سمتی دیگر، کلاس‌هایی که یک نوع از عملیات را پیاده‌سازی می‌کنند، از کلاس Visitor ارث‌بری می‌کنند. هرکدام از این کلاس‌های پسر به‌ازای هر کلاس پسر Element باید یک تابع را در درون خود پیاده‌سازی بکنند.مشتری‌ای که استفاده‌کننده‌ی بیرونی از این ساختار است، فقط نسبت به کلاس‌های پدر Element و Visitor دید دارد. اینکه مشتری از چه کلاس‌های عینی در هنگام اجرا استفاده کند، عموما توسط یک پیکربند مشخص می‌شود. در نتیجه، این الگو از نوع محدوده شیء است.عواقباز آنجا که این الگو باعث افزایش انسجام کلاس‌های از نوع Element می‌شود، به پیروی بیشتر از اصل یک‌مسئولیتی کمک شایانی می‌کند.باتوجه به نمودار کلاسی الگو، نقضی از اصل جایگزینی لیسکوف دیده نمی‌شود و تمام کلاس‌های پسر عملیات‌های ذکر شده در کلاس‌های پدر را پیاده‌سازی می‌کنند و قاعده‌ی «بیشتر انتظار نداشته‌باش و کمتر ارائه نده» برقرار است.کلاس Element و پسرهایش فقط به کلاس پدر Visitor وابسته هستند و اصلا نسبت به کلاس‌های پسر وابستگی‌ای ندارند. در نتیجه،‌ در این وابستگی اصل وارونگی وابستگی برقرار است. اگرچه از سمت دیگر این وابستگی، کلاس‌های پسر Visitor به کلاس‌های پسر Element به‌صورت مستقیم وابستگی دارند، که این نقض اصل وارونگی وابستگی است.از آنجا که در این مسئله یک نوع مشتری بیشتر نداریم، اصل جداسازی واسط در این الگو آن‌چنان موضوعیت ندارد.هنگام استفاده از این الگو، از آنجا که کلاس‌های Visitor یک عملیات از کلاس‌های عینی Element را پیاده‌سازی می‌کنند، عموما نیاز است به داخل آن کلاس‌ها دسترسی پیدا کنند. در نتیجه، این الگو اصل حداقل دانش را نقض می‌کند.از آنجا که در کلاس‌های Element یک‌سری از عملیات را به کلاس‌های دیگر واگذار کرده‌ایم، اصل استفاده مجدد مرکب برقرار است.از آنجا که در وابستگی از سمت کلاس‌های Element به کلاس‌های Visitor اصل وارونگی وابستگی برقرار است، برای اضافه‌کردن کلاس جدید Visitor غیر از تعریف خود کلاس، نیازی نیست قسمت دیگری از کد را تغییر دهیم. در نتیجه، اصل باز-بسته در این قسمت برقرار است. اما در وابستگی از سمت کلاس‌های از نوع Visitor به کلاس‌های از نوع Element چون اصل وارونگی وابستگی برقرار نیست، برای اضافه‌کردن یک کلاس جدید از نوع Element، علاوه بر پیاده‌سازی تابع accept در درون آن، نیاز است در تمامی کلاس‌های از نوع Visitor یک تابع جدید اضافه و پیاده‌سازی کنیم. در نتیجه،‌ در این قسمت اصل باز-بسته برقرار نیست. باتوجه به تحلیل‌های فوق، بهتر است هنگامی از این الگو استفاده کنیم که کلاس‌های از نوع Element ثبات داشته باشند.در این الگو، به علت رعایت اصول یک‌مسئولیتی، وارونگی وابستگی، و جایگزینی لیسکوف، از بین الگوهای GRASP الگوهای اتصال کم و انسجام زیاد و غیرمستقیم‌سازی و چندریختی نمود دارند و به علت نقض اصل حداقل دانش، الگوی متخصص اطلاعات نقض شده‌است.ارتباط با دیگر الگو‌های GoFالگوی مرکب: می‌توان برای انجام عملیات روی ساختارهای تعریف شده توسط این الگو، از الگوی بازدید کننده استفاده کرد.الگوی مفسر: می‌توان از یک کلاس عینی Visitor برای انجام عمل تفسیر استفاده کرد.کلام آخراین تحقیق تلاش داشته است علاوه بر توضیح و معرفی کتاب مفصل الگوهای طراحی دسته‌ی چهارنفره، روشی برای درک و به کارگیری الگوهای این کتاب معرفی کند. از این رو در بخش اول این تحقیق اصول طراحی شی‌گرا مرور کوتاهی شد که به قطع برای درک عمیق‌تر از آن‌ها (۱) باید مراجع این تحقیق - و همچنین دیگر مراجع مطرح این حوزه - مورد بررسی قرار گیرند و (۲) تجربه‌های عینی با استفاده از این اصول برای قرائت کننده حاصل شود. در بخش متاخر این تحقیق به بررسی نمونه‌هایی از الگو‌های طراحی این کتاب با در نظر داشتن اصول پیش‌تر معرفی شده، پرداخته شد.لازم به ذکر است اگرچه در این تحقیق رجوع مستقیمی به «طراحی مبتنی بر قرارداد» (از [۳]) و «ایجاد مبتنی بر مولفه» (از [۸]) نشده است، اما محتوای این نگاشت شدیدا تحت تاثیر این دیدگاه‌ها بوده است و از این رو توصیه می‌شود قرائت‌کننده، پس از بررسی این تحقیق، مطالعات کافی بر این موارد نیز داشته باشد.همچنین در بخش‌های مختلف این تحقیق، علی الخصوص نمودارهایی که ساختار ایستای هر الگو را توضیح می‌دهند (نمودارهای کلاسی هر الگو) از نمادگذاری UML استفاده یا به آن ارجاع شده است که دانش حداقلی و کافی از این نمادگذاری می‌تواند از کتابِ [۹] دریافت شود.در نهایت امید است این تحقیق انگیزه‌ای شود که قرائت‌کننده به دانش عمیق‌تری از اصول و الگوهای ترند مهندسی نرم‌افزار (علی‌الخصوص حوزه‌ی شی‌گرا) علاقه‌مند شود.واژه‌نامهمعادل فارسی نام الگوهای دسته‌ی چهارنفرهمتد کارخانه ← Factory Method، مفسر ← Interpreter، کارخانه انتزاعی ← Abstract Factoryمتد قالب ← Template Method، سازنده ← Builder، زنجیره‌ی وظایف ← Chain of Responsibilityنمونه‌اولیه ← Prototype، دستور ← Command، یگانه ← Singleton، تکرارگر ← Iteratorآداپتور ← Adapter، میانجی ← Mediator، پل ← Bridge، خاطره ← Momento، مرکب ← Compositeمشاهده‌گر ← Observer، دکوراتور ← Decorator، حالت ← State، نما ← Facadeراهبرد ← Strategy، مگس‌وزن ← Flyweight، بازدیدکننده ← Visitor، پروکسی ← ProxyمراجعGamma, E., Helm, R., Johnson, R., Vlissides, J., Design Patterns: Elements of Reusable Object-Oriented Software.Martic R., C., Design Principles and Design Patterns.Meyer, B., Object-Oriented Software Construction, 2nd Edition.Larman, C., Applying UML and Patterns: An Introduction to Object-Oriented Analysis and Design and Iterative Development, 3rd Edition.Lieberherr, K., Holland, I., Riel, A., Object-Oriented Programming: An Objective Sense of Style, Cullinane Hall, College of Computer Science, Northeastern University, 1988.Martin, R., C., Agile Software Development, Principles, Patterns, and Practices, 1st Edition.Pressman, R., S., Maxim, B., R., Software Engineering: A Practitioner's Approach, 8th Edition.Arlow, J., Neustadt, I., UML 2 and the Unified Process: Practical Object-Oriented Analysis and Design, 2nd Edition.Fowler, M., UML Distilled, 3rd Edition.