دسته: شي گرايي

الگو های طراحی (Design Pattern)

الگو های طراحی (Design Pattern) :

 

کسی وجود دارد که قبلاً مسله شما را حل کرده است.

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

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

 

تاریخچه الگو های طراحی :

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

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

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

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

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

در اوایل دهه 1990، افرادی زیادی روی الگوهای طراجی کار می کردند. اما چهار نفر به نام های، گاما، جاکوبسون، هلم و ولسایدز بیشترین تاثیر را در این زمینه با نوشتن کتابی به نام

“Design Pattern: Elements of Reusable Object-Oriented Software”، داشتند. این چهار نویسنده به Gang of Four مشهور است. آنها در این کتاب ائده استفاده از الگوها را در طراحی نرم افزار به کار بردند.و یک فرمت استاندارد را برای مستندسازی الگوها ایجاد کردند. 23 نوع از الگوها را دسته بندی کردند و …. به مرور زمان فرمت های استاندارد دیگری برای مستند سازی الگوها پیشهناد شد.

 

 قالب مستند سازی برای الگوهای طراحی :

 

 

نام الگو

یک نام خوب و مفید برای الگو

هدف (intent)

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

نام مستعار

نام های دیگری که الگو با آن شناخته می شود.

ساختار

یک نمایش گرافیکی از الگو

اجزاء تشکیل دهنده (Participants)

کلاس ها و اشیائ که در الگو شرکت دارند (وجود دارند).

همکاریها (Collaborations)

چگونه اجزای تشکیل دهنده با هم همکاری می کنند تا وظایفشان را انجام دهند.

نتايج‌ (Consequences)

نتایج استفاده از الگوی مورد نظر

پیاده سازی

تکنیک های برای پیاده سازی الگوی مورد نظر

نمونه کد

تکه کدی برای پیاده سازی یک نمونه

الگو های مرتبط

الگوهای طراحی دیگری که ارتباط نزدیگ با الگوی مورد نظر دارند.

 

دسته بندی الگو ها :

1-   الگوهای بوجود آورنده(Creational Pattern): همه الگو های که در این دسته قرار می کیرند در ارتباط با روش های ایجاد اشیاء هستند.

2-   الگوهای ساختاری(Structural Patten): این نوع الگوها شرح می دهند چگونه اشیاء و کلاس ها می توانند در ساختارهای بزرگتر باهم ترکیب شوند.

3-      الگوهای رفتاری(Behavioral Pattern): این نوع الگو ها روی ارتباط اشیاء با یکدیگر تمرکز دارند.

 

Creational

Structural

Behavioral

Factory Method

Abstract Factory

Builder

Prototype

Singleton

Adapter

Bridge

Composite

Decorator

Flyweight

Façade

Proxy

Interpreter

Template Method

Chain of Responsibility

Command

Iterator

Mediator

Memento

Observer

State

Strategy

Visitor

 

فهرست الگوهای طراحی

 

 

الگوی Iterator

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

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

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

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

دیاگرام الگوی Iterator

تعریف اینترفیس IIterator

Public Interface IIterator

 Function FirstItem() As Object

 Function NextItem() As Object

 Function IsDone() As Boolean

 Function CurrentItem() As Object

End Interface

 

پیاده سازی اینترفیس IIterator

Public Class ConcreteIterator

 Implements IIterator

 Private List As New ArrayList

 Private Current As Integer = 0

 

 Public Sub New(ByVal VarList As ArrayList)

 List = VarList

 End Sub

 

 Public Function CurrentItem() As Object Implements IIterator.CurrentItem

 Return List(Current)

 End Function

 

 Public Function FirstItem() As Object Implements IIterator.FirstItem

 Current = 0

 If IsDone() Then

 Return List(Current)

 Else

 Return Nothing

 End If

 End Function

 

 Public Function IsDone() As Boolean Implements IIterator.IsDone

 If Current >= List.Count Then

 Return False

 Else

 Return True

 End If

 End Function

 

 Public Function NextItem() As Object Implements IIterator.NextItem

 Current += 1

 If IsDone() Then

 Return List(Current)

 Else

 Return Nothing

 End If

 End Function

End Class

 

تعریف اینترفیس Aggregate

Public Interface IAggregate

 Function CreateIterator() As IIterator

End Interface

 

پیاده سازی اینترفیس Aggregate و کلاس Book

Public Class Book

 Implements IAggregate

 Private _Name As String

 Private _Chapters As New ArrayList

 

 Public Property Name() As String

 Get

 Return _Name

 End Get

 Set(ByVal value As String)

 _Name = value

 End Set

 End Property

 

 Public Sub New()

 

 End Sub

 

 Public Sub New(ByVal VarName As String)

 _Name = VarName

 End Sub

 

 Public Sub Add(ByVal Chapter As Chapter)

 _Chapters.Add(Chapter)

 End Sub

 

 Public Function CreateIterator() As IIterator Implements IAggregate.CreateIterator

 Return New ConcreteIterator(_Chapters)

 End Function

End Class

 

 

تعریف کلاس Chapter

Public Class Chapter

 Private _Name As String

 Public Property Name() As String

 Get

 Return _Name

 End Get

 Set(ByVal value As String)

 _Name = value

 End Set

 End Property

 Public Sub New()

 

 End Sub

 Public Sub New(ByVal VarName As String)

 _Name = VarName

 End Sub

End Class

 

نحوه استفاده

Dim Book As New Book(“Book1”)

Book.Add(New Chapter(“Chapter 1”))

Book.Add(New Chapter(“Chapter 2”))

 

Dim Iterator As IIterator = Book.CreateIterator

Dim Ins As Chapter = Iterator.FirstItem

While Iterator.IsDone

 System.Console.WriteLine(Ins.Name)

 Ins = Iterator.NextItem

End While

 

 

الگوی Composite

همانطوریکه روی صندلی نشسته اید به بدن خود تان توجه کنید و آنرا مورد بررسی قرار بدهید، شاید بدن خود را به صورت ترکیبی از چندین شی مانند دست، پا، چشم و …  ببینید. سپس با دست خود یک کتاب را بردارید و شروع به ورق زدن آن بکنید، مشاهده می کنید که یک کتاب از ده ها صفحه تشکیل شده است و هر صفحه از چندین پارگراف و هر پار گراف از چندین سطر تشکیل شده است.  روی آیکون My Computer کلیک می کنید، دریواهای که کامپیوترتان دارید نشان داده می شود، روی یکی از دریواها کلیک می کنید، لیست فایل ها و folder های آن دریوا نشان داده می شود، سپس روی یکی از folder ها کلیلک می کند، مشاهده می کند که خود آن folder، از چندین folder و یا فایل تشکیل شده است. در هر کدام از نمونه های بالا، همانطوریکه دیدید یک شی ممکن شامل چندین شی ساده یا مرکب دیگر نیز باشد، آن شی باید بداند که چگونه این اشیاء را نگهداری و مدیریت کند و هر چه تعداد اینگونه اشیاء مرکب در سیستم افزایش یابد، سیستم پیچیده تر خواهد شد. شما برای حل این مشکل چه پیشنهادی دارید و چه راه حلی ارائه می کنید؟

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

با این طراحی  Clinet می تواند یک مجموعه از اشیاء FileSystemComponent را ایجاد کند. و با استفاده از متد addComponent، شی  DirComponent، نمونه های مختلفی از FileSystemComponents را به DirComponent اضافه کند.

هنگامیکه Clinet بخواهد سایز هر کدام از این اشیاء را استخراج کند، به سادگی متد getComponentSize را فراخوانی کند، Client نباید از نحوه محاسبه و عملیاتی که برای اندازه گیری سایز یک مولفه صورت می گیرد آگاه باشد. در این مورد، client با هر دو شی FileComponent و DirComponent به یک صورت رفتار می کند.

Clinet  در مورد متد مشترک getComponentSize، با هر دو شی  FileComponent و DirComponent رفتار یکسانی را دارد. اما Clinet   برای فراخوانی متدهای مانند addComponent و getComponent نیاز دارد که دو شی را از همدیگر تشخیص دهد، چونکه این متدها فقط برای DirComponent تعریف شده است. به همین دلیل client نیاز دارد تا نوع شی مورد نظر را برای فراخوانی این متدها چک کند تا مطمئن شود که با یک نمونه از DirComponent سر و کار دارد.  برای بهبود این طراحی بگونه ای که نیازی به تشخیص تفاوت بین دو شی وجود نداشته باشد، طراحی را به چه صورت تغییر می دهد.

ما می خواهیم طراحی را بگونه ای تغییر دهیم که clinet  نیازی به تشخیص شی مرکب DirComponent از FileComponent نداشته باشد، و با هر دو شی به یک صورت رفتار کند.

طراحی را می توانیم به این صورت تغییر دهیم که، متدهای addComponent و getComponent را به اینترفیس مشترک FileSystemComponent  انتقال دهیم، و یک پیاده سازی پیش فرض برای این متدها انجام دهیم و اینترفیس مشترک FileSystemComponent   را به یک کلاس abstract تغییر دهیم. پیاده سازی پیش فرض برای این متدها بخاطر FileComponent  هست و کار خاصی را انجام نمی دهد. اما کلاس DirComponent این متدها را بازنویسی مجدد می کند تا پیاده سازی خاص خود را انجام دهد.

با این کار مشکل قبلی ما حل می شود، چون کلاس پدر FileSystemComponent، دارای یک پیاده سازی پیش فرض برای متدهای addComponent و getComponent هست، و دیگر clinet   نیاز به کنترل نوع شی برای فراخوانی این دو متد ندارد.

تصور کنید که می خواهیم یک متد جدید با نام  removeComponent را به کلاس DirComponent اضافه کنیم، در اینصورت این متد را به پدر FileComponent نیز اضافه می کنیم و یک پیاده سازی پیش فرض برای این متد در نظر می گیریم.

با طراحی بالا ما توانستیم مشکل خود را حل کنیم، اما روشی که برای غلبه بر مسئله استفاده کردیم، الگوی Composite نام دارد. ما در مواقعی از این الگو استفاده می کتیم که یک شی پیچیده داریم و می خواهیم آنرا به یک سلسله مراتب از اشیاء کل و جز (part-whole hierarchy) تجزیه کنیم. یا همانند مثال بالا،  client قادر باشد تفاوت بین اشیاء مرکب (DirComponent) و اشیاء منفرد را نادیده بگیرید. و client با همه اشیاء موجود در ساختار مرکب بصورت یکسان رفتار کند.

کلاس دیاگرام این الگو به صورت زیر است:

در دیاگرام بالا کلاس Leaf، کلاس های هستند که دارای فرزند نیستند مانند کلاس FileComponent در مثال.

کلاس Composite، کلاسی مانند DirComponent در مثال می باشد. در این کلاس رفتارهای مربوط به مولفه های که دارای فرزند هستند تعریف می گردد.

کلاس FileSystemComponent همان کلاسFileSystemComponent با ویژگیهای که در بالا اشاره شد هست.

نگرشی نو به شی گرایی

داستان از این قراره که روزی یک نفر از دهی به شهر میاد و از قضای روزگار به یک کنسرت موسیقی میره. در بازگشت از شهر در راه به مطرب ده میرسه که داشته با پسرش ساز و دهل میزده. همین که مطرب رو می بینه بهش میگه که من توی شهر رفتم یک جایی به اسم کنسرت و کلی از همکارات رو یک جا دیدم. مطرب هم که تا به اون روز کنسرت ندیده و نشنیده بوده، با بهت می پرسه که کنسرت چیه؟

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

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

منبع : در گذار عمر

شی (مقاهیم شی گرایی)


شما دنیا را چگونه می بینید ؟

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

 

یک شی چست ؟

یک شی می تواند یک موجودیت فیزیکی باشد ، مانند یک کتاب ، یک صندلی. شما می توانید یک کتاب را توصیف کنید ، آنرا بخوانید و آنرا بخرید.

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

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

  1. صفات(attributes) : صفات ویژگیهای یک شی را بیان می کند. در واقع یک صفت یک ویژگی از یک شی است مانند صفت نام برای یک فرد. صفات توصیف کننده یک شی هستند و با استفاده از مقادیر صفات می توان وضعیت فعلی یک شی را بدست آورد. برای مثال یک فرد می تواند دارای صفت تاهل باشد که با استفاده از مقدار این صفت می توان وضعیت تاهل آن فرد را در شرایط فعلی بدست آورد.
  2. رفتار(behaviors): یک رفتار عملی است که یک شی توانایی انجام دادن آن را دارد. برای مثال یک شخص می تواند راه برود ، بدود ، بنشیند و هزاران کار دیگری که قادر به انجام دادن آن است که هر کدام از این کارها برای آن شخص یک رفتار محسوب می شود. یک سوال یک کتاب می تواند چه رفتاری داشته باشد. آیا یک کتاب قادر به انجام دادن کاری است تا به عنوان یک رفتار برای آن شی به حساب آید ؟ شی کتاب در حقیقت قادر به انجام هیچ کاری نیست. یک ناشر برای انتشار یک کتاب کارهای مانند ویرایش کتاب ، چاپ کتاب ، توزیع کتاب و در آخر فروش کتاب را انجام می دهد. این کارها توسط یک نفر بر روی کتاب انجام می گیرد. متدلوژی شی گرا به ما می گوید که این رفتارها را به جای فردی که این کارها را انجام می دهد را به شی کتاب تخصیص بدهیم.

اصل (DRY (Don’t Repeat Yourself

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

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

 اما یک دلیل که فکر کنم ریشه روانشناسی هم داشته باشد در سالهای اول دانشگاه بوجود می آید و بعدها بعضی ها نمی توانند ترک کنند. شاید جملاتی مانند این که پروژه من چند هزار سطر شد و یا شبیه آن برای خیلی از دوستان آشنا باشد. جملاتی که در ترمهای اول دانشگاه تکرار می شود و تعداد سطرها بدون توجه به هر اصل دیگر، عامل اصلی برتری یک پروژه در بین گروه خاص از دانشجویان می شود. و سپس بعضی از دوستان نمی توانند از دام این عامل برتری خلاص شوند. و اغلب مشکلاتی که بخاطر این مسئله در برنامه هایشان بوجود می آید را با جملاتی مانند اینکه پروژه در این حجم (از لحاظ تعداد سطرها) نگهداریش واقعا مشکل و کار هر کسی نیست و … را تکرار می کنند. و صدها دلیل کوچک و بزرگ می توان پیدا کرد که می تواند عامل مشکل بالا باشد. اما برای رفع این مشکل بد نیست که یک اصل را به نام DRY (Don’t Repeat Yourself ) را مرور کنیم.

تعریف اصلی DRY

DRY: Every piece of knowledge must have a single, unambiguous, authoritative representation within a system.

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

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

class Line {

public:

Point start;

Point end;

double length;

};

تکه کد بالا را در نظر بگیرید، فکر می کنید مشکلی روی این کد وجود دارد یا نه. شاید در نگاه اول این کد مشکل نداشته باشد اما در این تکه کد اصل DRY رعایت نشده است. صفت length را در نظر بگیرید، مقدار این صفت با توجه به مقادیر start و end محاسبه می شود و با تغییر هر کدام از این صفات، آن نیز تغییر می کند (همیشه این نوع تکرار کد را با افزونگی در پایگاه داده مقایسه می کنم و می کویم صفتی که  قابل محاسبه از روی صفات دیگر باشد، نیازی به ذخیره سازی ندارد. می شود نرمالسازی در پایگاه داده را مفهومی مشابه این اصل دانست). پس بهتر است این تکه کد به صورت زیر تغییر کند.

class Line {

public:

Point start;

Point end;

double length() { return start.distanceTo(end); }

};

 

می توانیم به سادگی راه حل های زیادی برای رهایی از این دام پیدا کنیم و فکر می کنم نیاز زیادی به بحث روی این موضوع نیست، البته پیشگیری مثل همیشه بهترین شیوه درمان است. اما دوست دارم ادعای جالبی که آقایان  Andy Hunt و  Dave Thomas(اصل DRY، برای اولین با توسط این دو نفر ارائه شده است.) رابیان کنم و دوست دارم نظر شما را در مورد این ادعا بدانم. به نظر شما مرحله نگهداری یک برنامه  از چه زمانی شروع می شود؟ نمی دانم دقیقا پاسخ شما چیست، اما پاسخ دو نفر بالا به این صورت است که برنامه نویسان همیشه در مرحله نگهداری هستند.  و تنها در 10 دقیقه اول یعنی زمانیکه شما برای اولین با یک تکه کد را تایپ می کنید در مرحله نگهداری قرار ندارید و سپس شما بارها و بارها یک تکه کد را تغییر می دهید تا به هدف خود برسد و اینها جزء مرحله نگهداری هستند. حال نظر شما چیست؟

برچسب‌ها:

اصل open-closed

یک توسعه دهنده نرم افزار باید همیشه یک چیز را در ذهنش داشته باشد، در غیر اینصورت باید هزینه زیادی را متحمل شود یا حتی بدتر، باید شاهد مرگ محصولش باشد. تغییر.

مهم نیست که شما کجا کار می کنید، روی چه محصولی کار می کنید و با کدام زبان برنامه نویسی، برنامه نویسی می کنید. یک چیز، همیشه می تواند رخ بدهد. تغییر.

تنها یک چیز تغییر نمی کند. تغییر.

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

اصل open-closed

موجودیت های نرم افزاری برای نمونه کلاس ها، توابع و پیمانه ها باید برای توسعه باز باشند(اجازه داشته باشند)، اما برای تغییر باید بسته باشند(اجازه تغییر را ندارند).

یک تشبیه زیبا(فکر می کنم به زبان اصلی خیلی زیباتر است.)

Code should be closed(to change) like the lotus in the evening. Yet open(to extension) like the lotus flower in the morning.

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

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

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

If TypeOf S Is Circle Then

DrawCircle()

ElseIf TypeOf S Is Triangle Then

DrawTriangle()

Elseif

End If

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

حالا تصور کنید که کلاس انتزاعی یا یک اینترفیس به نام Shape تعریف کرده ایم که دارای یک متد به نام Draw می باشد، و تمام اشکال این متد را به ارث می براند و متد Draw را بازنویسی می کنند. در این حالت هر شکلی  جدیدی به برنامه اضافه شود، کلاس shape را به ارث می برد و متد Draw را بازنویسی می کند و نیازی نیست که در کلاس DrawManager تغییری ایجاد کنم و این کلاس، تنها متد Draw هر شکل را برای رسم آن شکل فراخوانی می کند. همانطوریکه مشاهده کردید ما در این حالت در کد مربوط به هیچ یک از کلاس های موجود تغییری ایجاد نکردیم اما برنامه خود را توسعه دادیم.

در بسیاری از الگوهای طراحی یکی از مهمترین ویژگیهای که در نظر گرفته شده است، اصل open-closed می باشد. برای نمونه می توانید الگوی TEMPLATE را بررسی کنید. ما باید بعضی از تغییراتی که می تواند در سیستم رخ دهد را، پیش بینی کنیم و با استفاده از مفهوم abstractions از سیستم خود در مقابل این تغییرات حفاظت کنیم. در واقع می توان گفت که کلید اصل open-closed دو مفهوم abstractions و encapsulation می باشد.

الگوی Decorator

وارد فروشگاه می شوید، غرفه ها را یکی یکی نگاه می کنید، بدنبال یک هدیه مناسب برای یک شخص خاص هستید. با زحمت و وسواس زیاد آنرا انتخاب می کنید و به فروشنده تحویل می دهید و می گوید آنرا برایتان کادو و تزئین کند. فروشنده جعبه های تزیئنی مختلف را برای قرار دادن هدیه برای شما نشان می دهد تا یکی از آنها را انتخاب کنید. شما جعبه مورد نظر را انتخاب می کنید. و پیشنهاد می کنید در صورت امکان بعد از قرار دادن هدیه شما و پیچیدن آن در کاغذ کادو، یک شاخه کل روی آن بچسباند. کار تمام می شود. فروشنده می گوید قیمت هدیه ای که انتخاب کرده اید، X تومان است، قیمت جعبه Y تومان است و فیمت شاخه گل  Z تومان است. شما باید سر جمع X+Y+Z تومان را پرداخت کنید.

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

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

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

در حال طراحی اینترفیس (UI) برنامه هستید، ترجیح می دهید که اطراف بعضی از دکمه ها (button) یک نوار رنگی نازک باشد. اما دکمه های  که شما استفاده کرده اید، این قابلیت را ندارد. می خواهید خودتان این قابلیت را به دکمه ها اضافه کنید. شما این کار را به چه روشی انجام می دهید؟

طراحی های مختلفی را می توان برای  هر دو مسئله بالا ارائه داد. اما یک طراحی و راه حل خوب الگوی Decorator است.

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

 

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

در مثال اول، شما یک هدیه، یک جعبه و یک گل می خرید. فرضی کنید می خواهیم، مقدار کل را با الگوی Decorator محاسبه کنیم:

در ابتدا یک شیی از کلاس هدیه 1 ایجاد می کنیم. این کلاس یک متد به نام قیمت برای محاسبه قیمت خود دارد.

هدیه 1  قیمت ()

سپس مشتری یک جعبه را انتخاب کرده بود، و فروشنده هدیه را در داخل آن قرار داده بود. پس ما نیز همین کار را می کنیم، یعنی فرضا نمونه ای از جعبه 1 را ایجاد می کنیم و شی هدیه ایجاد شده را در داخل آن قرار می دهیم. و هدیه را با جعبه تزئین می کنیم.

جعبه 1 قیمت()

هدیه 1  قیمت ()

 

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

گل قیمت()

جعبه 1 قیمت()

هدیه 1  قیمت ()

 

حل مشتری مبلغ پرداختی را از فروشنده می پرسد. پس ما باید در این نقطه قیمت را محاسبه کنیم. در ابتدا ما متد قیمت را از بیرونی ترین، تزئین کننده فراخوانی می کنیم. یعنی در ابتدا متد قیمت را برای شی گل فراخوانی می کنیم. این شی قیمت شی بعدی یعنی جعبه را فراخوانی می کند.  و جعبه متد قیمت، هدیه اصلی را فراخوانی می کند. در این نقطه چون هدیه یک شی تزئین کننده نیست (بلکه یک شی ConcreteComponent است). قیمت خود را برگشت می دهد یعنی 30000. سپس جعبه قیمت خود را به قیمت برگشت داده شده توسط هدیه، اضافه می کند. و مجموع را برگشت می دهدیعنی 31000. در آخر نیز گل مقدار خود را به مقدار برگشت داده شده اضافه می کند و مجموع کل را برگشت می دهد یعنی 33000. در پایین نحوه پیاده سازی الگو با همین آورده شده است.

کلاس Gift (Component)

Public MustInherit Class Gift

    Public MustOverride Function Cost() As Double

End Class

کلاس Decorator

Public MustInherit Class Decorator

    Inherits Gift

End Class

کلاس Gift1 (ConcreteComponent)

Public Class Gift1

    Inherits Gift

    Public Overrides Function Cost() As Double

        Return 30000

    End Function

End Class

کلاس Gift2 (ConcreteComponent)

Public Class Gift2

    Inherits Gift

    Public Overrides Function Cost() As Double

        Return 10000

    End Function

End Class

کلاس Box1 (ConcreteDecorator )

Public Class Box1

    Inherits Decorator

    Private Gift As Gift

    Public Sub New(ByVal Giftvar As Gift)

        Gift = Giftvar

    End Sub

    Public Overrides Function Cost() As Double

        Return 1000 + Gift.Cost

    End Function

End Class

کلاس Box2 (ConcreteDecorator )

Public Class Box2

    Inherits Decorator

    Private Gift As Gift

    Public Sub New(ByVal Giftvar As Gift)

        Gift = Giftvar

    End Sub

    Public Overrides Function Cost() As Double

        Return 1500 + Gift.Cost()

    End Function

End Class

کلاس Flower (ConcreteDecorator )

Public Class Flower

    Inherits Decorator

    Private Gift As Gift

    Public Sub New(ByVal Giftvar As Gift)

        Gift = Giftvar

    End Sub

    Public Overrides Function Cost() As Double

        Return 2000 + Gift.Cost

    End Function

End Class

ماژول Main

Sub Main()

        Dim Gift1 As Gift = New Gift1()

        Gift1 = New Box1(Gift1)

        Gift1 = New Flower(Gift1)

        System.Console.WriteLine(“Price = “ & Gift1.Cost)

 

        Dim Gift2 As Gift = New Gift2()

        Gift2 = New Box1(Gift1)

        Gift1 = New Flower(Gift1)

        System.Console.WriteLine(“Price = “ & Gift1.Cost)

        Console.ReadLine()

 

    End Sub

 

Observer Pattern

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

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

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

در هر دو مسئله بالا، ما یک شی داریم که مجموعه ای از اشیاء به آن وابسته هستند. هر زمانی که وضعیت شی مورد نظر تغییر می کند، اشیاء دیگر از آن تغییر آگاه می شوند. در این الگو، مجموعه اشیاء وابسته را Observer   های می نامیم و شی را که دیگر اشیاء به آن وابسته هستند را Subject می نامیم. برای نمونه در مثال اول، افرادی که در سایت عضو می شوند یک شی Observer   هستند. و شی خبر، همان  Subject  هست.

الگوی Observer  یک وابستگی،  یک به چند بین اشیاء هست، هنگامیکه شی طرف یک، وضعیتش تغییر کند، اشیاء وابسته مطلع می شوند و وضعیت خودشان را با توجه به آن وضعیت بروز رسانی می کنند.

مکانیزم عملکرد این الگو بصورت زیر است:

1-       Subject باید یک اینترفیس برای ثبت (registering) و انصراف از عضویت (unregistering) و اطلاع از تغییرات را آماده کند.

2-       Subject باید اطلاعات حالتی را که، observer ها برای آن ریجستر شده اند را به observer  ها ارسال کند.

3-       Observer  باید یک اینترفیس برای دریافت پیام از Subject آماده کند.

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

 

 

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

 

اینترفیس مربوط به subject

Public Interface subject

    Sub Attach(ByVal Ins As Observer)

    Sub Detach(ByVal Ins As Observer)

    Sub Notify()

End Interface

اینترفیس مربوط به Observer  

Public Interface Observer

    Sub Update(ByVal operation As String, ByVal record As String)

End Interface

کلاس database که اینترفیس مربوط به subject را پیاده سازی می کند.

Public Class dataBase

    Implements subject

    Private observers As ArrayList

    Private operation As String

    Private record As String

 

    Public Sub New()

        observers = New ArrayList

    End Sub

 

    Public Sub Attach(ByVal Ins As Observer) Implements subject.Attach

        observers.Add(Ins)

    End Sub

 

    Public Sub Detach(ByVal Ins As Observer) Implements subject.Detach

        observers.Remove(observers)

    End Sub

 

    Private Sub Notify() Implements subject.Notify

        For I As Integer = 0 To observers.Count – 1

            Dim Ins As Observer = observers(i)

            Ins.Update(operation, record)

        Next

    End Sub

    Public Sub editDatabase(ByVal ope As String, ByVal rec As String)

        Me.operation = ope

        Me.record = rec

        Notify()

    End Sub

 

End Class

کلاس Archiver که اینترفیس Observer   را پیاده سازی می کند.

Public Class Archiver

    Implements Observer

    Public Sub Update(ByVal operation As String, ByVal record As String) Implements Observer.Update

        MessageBox.Show(“The archiver says a “ + operation + ” operation was performed on “ + record)

    End Sub

End Class

کلاس boss که اینترفیس Observer   را پیاده سازی می کند.

Public Class Boss

    Implements Observer

    Public Sub Update(ByVal operation As String, ByVal record As String) Implements Observer.Update

        MessageBox.Show(“The boss says a “ + operation + ” operation was performed on “ + record)

    End Sub

End Class

 

کلاس client که اینترفیس Observer   را پیاده سازی می کند.

Public Class client

    Implements Observer

    Public Sub Update(ByVal operation As String, ByVal record As String) Implements Observer.Update

        MessageBox.Show(“The client says a “ + operation + ” operation was performed on “ + record)

    End Sub

End Class

 

تست

Dim DB As New dataBase

Dim Ar As New Archiver

Dim Bo As New Boss

Dim Cl As New client

DB.Attach(Ar)

DB.Attach(Bo)

DB.Attach(Cl)

DB.editDatabase(“Delete”, “Record 1”)

در مثال بالا، ما سه نوع Observer   داریم. که هر وقت تغییری در پایگاه داده اعمال می شود، با یک پیام به آنها اعلام می شود.

الگوها

یکی دیگر از نکات مثبت دیگر در الگوهای طراحی این است که آنها ماحصل تجربه‏اند و نه مباحث آکادمیک. به عبارت دیگر برای خلق یک الگو، لازم نیست شما در آزمایشگاههای مهندسی نرم‏افزار به دنبال کشف نمونه‏ای جدیدی از آن باشید، بلکه باید در حین تجربه و انجام کار، حواستان به گذشته‏تان باشد یا به آینده؛ و طرح این سئوال که آیا من درگذشته این مسئله را حل کرده‏ام؟ آیا مسئله‏ای که با آن روبرو هستم دیگر بار ممکن است تکرار شود؟( الگوهای طراحی، محاسن و معایب (Design Patterns Pros & Cons) )

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

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

استاد بزرگ و نگهبان، مراقبت از یک صومعه ذن را بین خود تقسیم کردند. یک روز، تکهبان در گذشت  و باید کس دیگری را جایگزین او می کردند.

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

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

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

استاد گفت: مساله این است.

شاگردها، حیران، به گلدان نگاه کردند: به طرح های پیچیده و نادر روی سفال، به تازگی و زیبایی گل. منظور چه بود؟ چه کار باید می کردند؟ معما چه بود؟

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

استاد گفت: تو نگهبان جدید مایی.

وقتی شاگرد به جای خودش برگشت، استاد بزرگ توضیح داد:

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

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