نشانه های طراحی بد

rigidity

  • اعمال ساده ترین تغییرات در نرم افزار مشکل است.
  • یک تغییر منجر به سلسله مراتبی از تغییرات می شود.
  • تعداد المان هایی که تحت تاثیر تغییرات قرار می گیرند زیاد است.و در واقع هر چه تعداد این المان ها بیشتر باشد rigidity بالا تر است.

fragility

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

immobility

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

viscosity

  • کار را نمی توانیم به روش درست انجام دهیم و طراحی ما را به پیاده سازی غلط هدایت می کند.

needless complexity

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

needless repetition

  • کدهای تکراری به وفور یافت می شوند.
  • یک باگ را باید در چندین جا رفع کرد.

opacity

  • درک و فهم یک ماژول بسیار سخت است و یا غیر ممکن است.

 


تعداد نمایش این پست: 13

Controller در اصول GRASP

مدتی قبل درباره الگوی Information Expert که یکی از الگوهای GRASP است نوشته بودم.همانطور که قبلاً نیز به آن اشاره کردم GRASP کمک می کند که با استفاده از یک سری اصول و الگوها وظایف را بین اشیا به درستی تقسیم کنیم.به طور مثال در مسئله محاسبه حقوق و دستمزد وظیفه محاسبه حقوق به عهده شی کارمند است یا یک شی دیگر.

GRASP تشکیل شده است از:

Controller
Creator
High Cohesion
Indirection
Information Expert
Low Coupling
Polymorphism
Protected Variations
Pure Fabrication

Controller اولین الگو در GRASP به سوالات زیر پاسخ می دهد:

  • چه کسی وظیفه دارد که رویداد های سیستم را مدیریت کند؟
  • چه کسی وظیفه مدیریت رویدادهای UI را دارد؟
  • چه کسی وظیفه مدیریت رویدادهای بیرونی را دارد؟

Controller بیانگر کلاسی است که وظیفه های بالا را انجام می دهد و به عبارتی دیگر Controller کلاسی است که پیچیدگی لایه domain را از دنیای بیرونی مخفی می کند.به طور مثال زمانیکه یک درخواست از سمت UI دریافت می شود الگوی Controller به ما کمک می کند که کدام شی وظیفه مدیریت کردن این درخواست را دارد این شی درخواست را دریافت می کند و سپس وظیفه پاس کردن آن را به سایر اشیا دامین بر عهده دارد.

Example for Controller

 


تعداد نمایش این پست: 11

Law of Demeter

یکی از مطالبی که قبل تر نوشتم در رابطه Cohesion و coupling بود.

طراحی خوب یعنی cohesion بالا و coupling پایین.

coupling یعنی چسبندگی کلاسها(و یا ماژولها) به یکدیگر به صورتیکه با تغییر یکی از آن مجبور شویم حجم زیادی از تغییرات را اعمال کنیم.برای رسیدن به مفهوم coupling پایین قطعا راه حل هایی وجود دارد.یکی از آن راه حل ها Law of Demeter است.

Law of Demeter شامل بنده های زیر می شود:

  • هر واحد باید اطلاعی اندک از سایر واحدها داشته باشد؛ البته تنها از واحدهایی که دارای رابطهٔ «نزدیک» با این واحد دارند،
  • هر واحد تنها باید با دوستانش حرف زند؛ از غریبه‌ها دوری کن
  • تنها با دوستِ نزدیکش حرف بزند

به عبارت دیگر زمانی که ما این قانون را رعایت کنیم از داخل یک شی به شی دیگر نخواهیم رسید.برای مثال اگر قرار باشد شی a از طریق شی b به شی c که به عنوان یک property در آن تعریف شده است برسیم قانون Law of Demeter را نقض کرده ایم.

b.c.Method()

باید توجه داشتیم باشیم رعایت هر قانونی مزایا و معایب خود را دارد ونمی توانیم همه جا از این قوانین استفاده کنیم و یا خود را مجبور به رعایت آن کنیم.
به طور مثال Phil Haack در رابطه با این قانون یک مطلب جالب نوشته است که استفاده از چند عدد نقطه(dot)پشت سره هم به معنای نقض این قانون نیست.


تعداد نمایش این پست: 7

Cohesion و coupling

Cohesion به این معنی است که کلاس قرار است چه کاری را انجام دهد.cohesion پایین به این معنی است که یک کلاس کارهای متفاوتی را انجام می دهد و تمرکزی روی کار اصلی که باید انجام دهد ندارد.در کلاس پایین دقت کنید Staff کارهای زیادی انجام می دهد که اصلا ربطی به وظیفه اصلی آن ندارند.

-------------------
| Staff           |
-------------------
| checkEmail()    |
| sendEmail()     |
| emailValidate() |
| PrintLetter()   |
-------------------

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

----------------------------
| Staff                   |
----------------------------
| -salary                 |
| -emailAddr              |
----------------------------
| setSalary(newSalary)    |
| getSalary()             |
| setEmailAddr(newEmail)  |
| getEmailAddr()          |
----------------------------

coupling به میزان وابستگی دو کلاس با یکدیگر اشاره می کند.در صورتی که coupling بالا باشد تغییر در یک کلاس باعث تغییر زیاد در کلاس مصرف کننده می شود.

طراحی خوب یعنی cohesion بالا و coupling پایین.

البته باید دقت کرد که Cohesion و coupling را برای ماژول ها نیز به کار می برند.


تعداد نمایش این پست: 23

Generalization و Specialization

Generalization و Specialization  مشخص کننده مجتمع کردن رفتار و خصوصیات در کلاس های پایه و یا کلاس های فرزند است.

Generalization:

درفرایند Generalization  رفتار و خصوصیات اصلی و مشترک همه کلاس ها(در سلسله مراتب) درون کلاس پایه جمع می شود.

Specialization :

Specialization برعکس Generalization  است و در واقع کلاس های فرزند نسبت به کلاس های پدر تخصصی تر عمل می کنند

به عنوان مثال:

وسیله نقلیه یک کلاس پایه است که درون خود رفنار روشن و خاموش شدن را دارد(Generalization).در حالیکه کشتی و ماشین کلاس های فرزند هستند و نسبت به کلاس پایه خود رفتار تخصصی تر را دارند(Specialization).

 

specialization


تعداد نمایش این پست: 20

کلاس چیست؟

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

کلاس مشخص کننده رفتار مشترک،ساختار مشترک و مفهوم مشترک بین اشیا است.

ارتباط بین کلاس ها:

۳ نوع ارتباط در کلاس ها وجود دارد:

  1. is a
  2. part of
  3. association

is a:

یک کلاس فرزند رفتار کلاس پایه خود را به ارث می برد.کلاس های فرزند امکان دارد رفتار کلاس پایه خود را تغییر دهند و یا به آن ها رفتاری اضافه کنند.کلاس هایی که نخواهیم از آن ها شی ساخته شود و به عبارتی generalize هستند را abstract class می نامیم.این کلاس های به این منظور ساخته می شوند که به آنها رفتاری اضافه شود و یا پیاده سازی یک سری رفتار توسط آنها بی معنی است.مثلا کلاس shape و متد drawدر کلاس shape .بی معنی است که از کلاس shape یک وهله بسازیم.

part of:

در این ارتباط یک کلاس قسمتی از یک کلاس دیگر است.

      1. aggregation:یک کلاس قستمی از کلاس دیگر است وصرفا با از بین رفتن کلاس اصلی(کل)کلاس درونی (جز )از بین نمی رود.
public class Foo { 
private Bar bar; 
Foo(Bar bar) { 
   this.bar = bar; 
}
 }
    1. composition:یک کلاس قسمتی از کلاس دیگر است ولی در صورتی که کلاس اصلی(کل) از بین برود کلاس درونی(جز)نیز از بین می رود.
public class Foo {
    private Bar bar = new Bar(); 
}

association:

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

polymorphism:

polymorphism یعنی فرم و یا رفتار متفاوت داشتن.سه نوع polymorphism داریم:

  1. Ad hoc polymorphism:همان  function overloading و یا operator overloading است.
  2. Parametric polymorphism:یک امکان وابسته به زبان برای داشتن تایپ های generic.
  3. Subtyping:به حالتی می گویند که کلاس فرزند رفتار کلاس پایه خود را تغییر بدهد.مثل method overriding.

 

 

 


تعداد نمایش این پست: 17

شی چیست؟

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

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

شی دارای سه خصوصیت زیر است:

  1. رفتار
  2. وضعیت
  3. شناسه

وضعیت(state):

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

رفتار (behaviors):

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

پنج نوع رفتار اصلی در اشیا داریم:

  1. modifier:تغییر دهنده وضعیت یک شی
  2. selector:گرفتن وضعیت یکی از خصوصیات شی
  3. iterator:کرفت یک سری از اشیا و یا وضعیت ها با ترتیبی مشخص
  4. constructor:سازنده شی
  5. destructor:تخریب کننده شی

رفتار یک شی مسئولیت های یک شی را نشان می دهد.

شناسه (identifier):

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

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

روابط اشیا با یکدیگر

اشیا دو ارتباط اصلی با یکدیگر دارند.

  1. link
  2. aggregation

link به معنی استفاده یک شی از شی دیگر است و یا به عبارت ساده تر method call را در اشیا link می گویند.

aggregation یعنی وجود یک شی درون شی دیگر.در این حالت می توان از یک شی به شی دیگر رسید.


تعداد نمایش این پست: 23

typing-concurrency-persistence

در ادامه بررسی عناصر شی گرایی در این پست سعی می کنم سه عنصر غیر اجباری شی گرایی یعنی typing,concurrency و persistence را معرفی کنم.

typing:

type یا نوع مشخص کننده خصوصیات یک شی است.در واقع type ما را در استفاده از یک شی به جای یک شی (از type )دیگر محدود می کند و معمولاً typeها قابل تبدیل به یکدیگر نیستند مگر اینکه از یک کلاس پایه باشند و یا عملیات casting انجام شود.typingزبان های برنامه نویس در رابطه با موضوع typing سه دسته هستند:

  • weakly type
  • untype
  • strongly type

دو نوع تقسیم بندی دیگر نیز وجود دارد:

  • Static
  • Dynamic

Static/Dynamic اشاره به زمانی دارد که type مشخص می شود(زمان کامپایل و یا زمان اجرا) در حالیکه Strong/Weak به معنای محدود ساختن عملیات روی typeها هست.مثلا تبدیل روی typeها.(type conversion)

concurrency

استفاده از چند thread و یا چند process برای انجام دادن عملیات مورد نظر.در مفهوم شی گرایی به objectی که یک thread مجزا برای اجرا دارد active objects گفته می شود.به عبارت دیگر برنامه پیچیده از تعدادی thread و یا process تشکیل شده است که برای رسیدن به اهداف سیستم به طور همزمان در حال کار هستند.

object-oriented

Persistence

یک شی در هر لحظه مقداری از حافظه رم را اشغال می کند.ذخیره خصوصیات و state اشیا در یک مکان را Persistence می گویند.

Persistenceتا به اینجا با هم با عناصر اصلی یک برنامه شی گرا یعنی:

و هم با عناصر ثانویه آن یعنی:

  • Typing
  • Concurrency
  • Persistence

آشنا شدید.عناصر ثانویه در یک برنامه شی گرا اجباری نیستند ولی کاربردی هستند.


تعداد نمایش این پست: 20

Hierarchy

در پست های قبلی درباره Abstraction,Encapsulation,Modularity  توضیحاتی را دادم و در این پست آخرین عنصر از عناصر شی گرا را معرفی خواهم کرد:Hierarchy

گریدی بوچ در رابطه با Hierarchy می گوید:

Hierarchy is the ranking or ordering of abstraction

Hierarchy

Hierarchy باعث استفاده مجدد از کدها می شود.دو نوع Hierarchy  در شی گرایی وجود دارد.

  1. رابطه is a
  2. رابطه part of

رابطه is a  همان ارث بری است که یک کلاس فرزند از کلاس پدر ارث بری می کند.

در رابطه با ارث بری دو نوع ارث بری وجود دارد.single inheritance و multiple inheritance.که زبان ها با توجه به پیاده سازیشان از یک یا هر دو نوع پشتیبانی می کنند.

Multiple_InheritanceSingle_Inheritance

در هنگام ارث بری یک اصل وجود دارد :اگر b یک نوع از a نیست بنابراین b نباید از a ارث بری کند.باید توجه کرد که به هنگام inheritance امکان دارد Encapsulation نقض شود و دلیل آن هم این هست که ممکن است در زمان ارث بری کلاس فرزند به پیاده سازی کلاس پدر وابسته شود.البته این به این معنی نیست که ارث بری کار غلطی هست inheritance از عناصر اصلی شی گرایی هست.

رابطه part of همان aggregation است.مثلا گلبرگ قسمتی از یک گیاه است.یا باغ شامل گل و گیاه می باشد.

aggregation oop

در پست های بعدی درباره عناصر فرعی شی گرایی یعنی typing,concurrency و persistence توضیح خواهم داد.


تعداد نمایش این پست: 15

مفهوم Modularity در طراحی شی گرا

در دو پست قبلی درباره abstraction و encapsulation صحبت کردم.در این پست یکی دیگر از عناصر برنامه نویس شی گرا را به اسم Modularity معرفی خواهم کرد.

Modularity

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

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

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

یادمان باشد که تفکر شی گرا باعث مدیرت و  کاهش پیچیدگی در برنامه می شود.


تعداد نمایش این پست: 29