محلی برای یادگیری جاوا

اصل اول Single Responsibility

اولین اصل تک مسیولیتی است:

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

مثالی که برای این موضوع می توان زد چاقوهای سوییسی هستند که یک وسیله چند مسیولیت دارد. و در صورت نیاز به تغییر مثلا تیغه ی قیچی تمام تیغه های دیگر نیز ممکن است تاثیر بپذیرند.

SingleResponsibility

ولی در صورت جدا بودن هر وسیله تعویض یا تغییر آن مستقل از دیگر وسایل است.

SingleResponsibility SOLID

۰۷ خرداد ۹۶ ، ۱۴:۱۱ ۰ نظر موافقین ۱ مخالفین ۰
پریسا

SOLID

SOLID سرنام پنج اصل از طراحی شی گرا (Object-Oriented Design) است.

S - Single-responsiblity principle

O - Open-closed principle

L - Liskov substitution principle

I - Interface segregation principle

D - Dependency Inversion Principle

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

۲۵ ارديبهشت ۹۶ ، ۱۳:۵۷ ۱ نظر موافقین ۰ مخالفین ۰
پریسا

بازگشت

سلام 

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

۲۴ ارديبهشت ۹۶ ، ۰۰:۴۸ ۱ نظر موافقین ۱ مخالفین ۰
پریسا

نکاتی برای نوشتن کد تمیز- کامنت ها

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

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

نکات مورد توجه در مورد کامنت ها:

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

کامنت های خوب:

  • کامنت های مجاز: که قوانین را اعلام می کنند. مثل کپی رایت.
  • کامنت های آموزنده: مثل کامنتی که فرمت تاریخ و زمان را نشان می دهد.
  • توضیح دادن مقصود: در صورتی که واقعا هدف را بیان کند.
  • شفاف سازی: باز هم اولویت با نوشتن کد شفاف است تا کامنت.
  • هشدار در مورد عواقب: فرض کنید یک متد sleep() داریم که زمان بر است. کامنت در مورد این موضوع می تواند خواننده را آگاه کند.
  • کامنت های To Do: کارهایی که باید انجام شوند اما تا الان انجام نشده اند.
  • تقویت:برای تقویت اهمیت چیزی که ظاهرا مهم به نظر نمی رسد.
  • java doc یا امکانات مشابه در سایر زبان ها

کامنت های بد:

  • کامنت های من من کننده
  • کامنت های زاید: کامنت های که خواندنشان بیشتر از خواندن کد وقت می گیرد.
  • کامنت های گمراه کننده
  • کامنت های اجباری
  • کامنت های ژورنالی: کامنت هایی که مثل لاگ در کد ایجاد می شود مثل نام نویسنده یا ویرایشگر و تاریخ.
  • کامنت های نویز: کامنت هایی که هیچ اطلاعاتی نمی دهند: مثل نوشتن کامنت default constructor
  • Position markers: //////////////// که برای جدا سازی استفاده می شود اگر زیاد باشد مثل نویز می شود و هیچ کمکی نمی کند.
  • کامنت های نزدیک کروشه و براکت ها: مثل end while// {  که وقتی حلقه خیلی طولانی باشد، جای بسته شدن حلقه ها را نشان می دهد. بهتر است به جای این کار طول توابع کمتر شود تا چایان حلقه ها راحت پیدا شود.
  • کد های comment-out: کد هایی که نوشته شده اند بعد کامنت شده و به حال خود رها شده اند.
  • کامنت های غیر محلی: هر کامنت باید نزدیک کد مربوط به خودش باشد.
  • اطلاعات اضافی و بیش از حد در کامنت
  • Function header ها: بهتر است به جای توضیح کار توابع یک نام خوب که کارش را نشان می دهد، انتخاب کنیم.
۲۹ بهمن ۹۴ ، ۱۰:۲۴ ۱ نظر موافقین ۲ مخالفین ۰
پریسا

نکاتی برای نوشتن کد تمیز- متدها

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

  • باید کوتاه باشد.
  • برای فهم بهتر در موارد لازم از تو رفتگی استفاده شود.
  • هر تابع باید فقط یک کار انجام دهد و آن را به خوبی انجام دهد.
  • برای اطمینان از اینکه تابع ما فقط یک کار انجام می دهد باید مطمین شویم تمام statement های درون تابع در یک سطح از abstraction هستند.
  • قانون Step down: میخواهیم کدها بصورت یک روایت از بالا به پایین خوانده شوند.
  • تا حد امکان switch-case استفاده نکنیم و آن را در پلی مورفیسم دفن کنیم. چون یک switch حتی با دو case هم طولانی است.
  • برای توابع از اسم های توصیفی استفاده کنید که عملکرد تابع از روی نام آن قابل فهم باشد.
  • تعداد آرگومان های تابع باید تا حد امکان کم باشد. ایده ال ترین حالت بدون آرگومان است و تعداد 3 و بیشتر، آرگومان فقط در موارد خیلی خاص باید استفاده شود.
  • از try/catch ها استفاده کنید.
۰۷ بهمن ۹۴ ، ۱۶:۴۵ ۰ نظر موافقین ۲ مخالفین ۰
پریسا

نکاتی برای نوشتن کد تمیز-نام های معنادار

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

 متغییر ها، توابع و کلاس ها همه نام دارند. نام گذاری درست در فهم کد و تمیز بودن آن بسیار موثر است:

  • از نام هایی که هدفشان معلوم است استفاده کنید.
  • از نام هایی که اطلاعات درست نمی دهند (disinformation) بپرهیزید. بعضی لغات معنای تثبیت شده ای در ذهن دارند. از این لغات برای معانی دیگر استفاده نکنید. برای مثال hp مربوط به پلتفرم unix است. اگر در کد خود وتر (hypotenues) دارید شاید ظاهرا hp نام خوبی برای آن به نظر برسد. اما گمراه کننده است و نباید از آن استفاده کرد.
  • از کلماتی مانند list تنها در کاربرد خودشان استفاده کنید. مثلا اگر گروهی از دانش آموزان دارید که در سیستم بصورت list نیستند متغییرشان را studentList نام گذاری نکنید. studentGroup نام بهتری ست.
  • از کلمات خیلی مشابه برای متغییر های مختلف استفاده نکنید. چون اشتباها به جای یکدیگر در نظر گرفته می شوند:

xyzControllerForEfficientHandelingOfSetting

xyzControllerForEfficientStorageOfSetting

  • از O و L تک استفاده نکنید چون با 0 و 1 اشتباه گرفته می شوند.
  • تفاوت های معنادار ایجاد کنید. مثلا a1 و a2 هیچ اطلاعاتی به ما نمی دهد (noninformative). تنها می توان فهمید که یک سری هستند.
  • تفاوت بی معنی ایجاد نکنید. در واقع از noise word استفاده نکنید. مثلا ProductData و ProductInfo هیچ تفاوتی ندارند. یا نام گذاری کلاس مشتری به CustomerObject درست نیست. چون Customer به تنهایی اطلاعات را می رساند و Object در ادامه ی آن اضافه است.
  • از نام های قابل تلفظ استفاده کنید. مثلا مخفف genymdhms، که مربوط به تاریخ و سال و ماه و... است، نام خوبی نیست. 
  • از نام های قابل جستجو استفاده کنید. مثلا اگر نام متغیر تک حرف باشد، سرچ آن هزار نتیجه دارد و پیدا کردن جواب سخت است. اما MAX_STUDENT به راحتی قابل پیدا کردن است.
  • تک حرف ها بهتر است تنها برای نام متغیرهای local استفاده شوند.
  • از کد کردن بپرهیزید. مثل استفاده از I در ابتدای نام interface ها و یا انتهای Imp در انتهای نام کلاس های پیاده ساز.
  • نام کلاس ها باید یک اسم یا یک عبارت اسمیه باشد.
  • نام متدها باید یک فعل یا یک عبارت فعلیه باشد.
  • بامزگی نکنید. چون نام های بامزه تنها در ذهن افراد درگیر شوخی می مانند.
  • برای هر مفهوم فقط از یک اسم استفاده کنید. مثلا برای گرفتن اطلاعات از get و fetch و retrieve و ... در کلاس های مختلف استفاده نکنید. بعدا از کجا باید بفهمید که کدام متعلق به کدام است و تفاوتشان چیست؟
  • برای مفاهیم متفاوت از یک اسم استفاده نکنید.
  • از نام های موجود در solution domain استفاده کنید. خوانندگان کد، برنامه نویس هستند و از لغات موجود در علم کامپیوتر مطلعند پس نام هایی مثل jobQueue یا accountVisitor مفهوم را می رساند.
  • کلمات با معنا در نام ها اضافه کنید. فرض کنید متغیر های firstname, lastname, country, state و ... را میبینید. با دیدن این متغیرها می فهمیم که مربوط به آدرس هستند. اما اگر فقط متغیر state را ببینیم چطور؟ آیا متوجه می شویم مربوط به آدرس است؟ می توانیم یک context با معنا به آنها اضافه کنیم که مشخص شود مربوط به آدرس اند. به این شکل: addrFirstname, addrLastname, addrCountry, addrState و ... با این نام گذاری خواننده می فهمد که این متغیرها مربوط به یک مفهوم بزرگترند. اما راه بهتر تعریف کلاس Address است که در این صورت علاوه بر خواننده، کامپایلر هم می فهمد که این متغییر ها به مفهوم بزرگتری وابسته اند.
  • کلمات بی معنا در نام ها اضافه نکنید. مثلا اگر نام پروژه Gas Station Delux است، منطقی نیست قبل از نام همه ی متغیر های برنامه GSD اضافه کنیم چون اطلاعاتی نمی دهد و نام ها را بدون هیچ مزیتی طولانی می کند.

در پست بعد در مورد توابع تمیز توضیح خواهم داد.

۲۱ دی ۹۴ ، ۰۹:۵۸ ۱ نظر موافقین ۱ مخالفین ۰
پریسا

Clean Code کد تمیز

حتما تا به حال در مباحث پیشرفته ی برنامه نویسی با عبارت کد تمیز یا Clean code مواجه شده اید.

اما سوال این است که چرا و چگونه کد تمیز بنویسیم؟ در این پست به چرایی و در پست های بعد به چگونگی نوشتن کد تمیز می پردازم.

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

http://www.amazon.com/Clean-Code-Handbook-Software-Craftsmanship/dp/0132350882

چرا کد تمیز؟

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

-maintain یا نگهداشت آن ساده تر است 

-یافتن bug ها ساده تر است

-bug ها کمتر هستند

-فهم آن ساده تر است

-...

یک سناریوی آشنا!

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

در چنین پروژه های با افزایش feature های پروژه این در هم ریختگی ها بیشتر می شود تا جایی که کد غیر قابل مدیریت می شود. اینجاست که گفته می شود bad code شرکت را به مرور ورشکست می کند!!

با بهم ریختگی کد با گذر زمان بهره وری یا productivity تیم رو به کاهش می رود تا جایی که به 0 میل می کند. مدیران در چنین مراحلی سعی می کنند با افزایش feature ها بهره وری تیم را بالا ببرند اما اینکار به نتیجه نمی رسد. چون با این کار درهم ریختگی کدها بیشتر و بیشتر می شود. تیم به هم می ریزد و develop روی کدهای موجود امکان ادامه ندارد در نتیجه درخواست طراحی یک سیستم جدید داده می شود.

مدیران نمی توانند تمام منابع را به طراحی سیستم جدید اختصاص دهند و همچنین نمی توانند انکار کنند که سیستم موجود قابل ادامه نیست پس یک تیم جدید انتخاب می شود (TIGER team). همه افراد دوست دارند در این تیم باشند چون پروژه ی آن green field است.

tiger team پروژه ی خوبی تولید می کند اما فقط برای خودش، و بقیه مجبور به کار با سیستم قبلی اند. سیستم جدید باید تمام ویژگی های سیستم قبلی را داشته باشد و علاوه بر آن باید تمام تغییرات ممتد سیستم قدیمی را نیز پوشش دهد.

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

پس طبق آنچه گفته شد clean code یک موضوع cost effective نیست، بلکه مسیله ایست برای بقای حرفه ای پروژه.

پی نوشت:

TIGER team: سر آمد  Totally Integrated Group of Expert Resources است. در واقع جمعی از خبرگان برای تحقیق و حل یک مشکل فنی.

green field project: پروژه ای که محدود و مقید به پروژه های قبلی نیست.

۰۹ دی ۹۴ ، ۱۰:۵۵ ۳ نظر موافقین ۱ مخالفین ۰
پریسا

Abstraction یا تجرید

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

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

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

  

abstarction

  

پس برای کد کردن مثال زیر ما یک کلاس Abstract به نام Automobile می سازیم که همانطور که می دانید قابل نمونه سازی نیست و به عنوان پدر کلاس هایی مثل Bus، Car و ... استفاده می شود.

public abstract class Automobile {

protected String type;
protected int numberOfDoor;
.
.
.

protected abstract void Drive();
...
}

حالا برای مثال از این کلاس برای ارث بری استفاده می کنیم:

public class Car extends Automobile {


@Override
protected void Drive() {

}

public Car()
{

}
}

همانطور که دیده می شود متد Drive از کلاس پدر Override شده است و اینکار اجباریست چون Drive در کلاس پدر بدنه ندارد. 

در مرحله آخر شی pride را می سازیم و از آن استفاده می کنیم:

public class Main {
public static void main(String[] args) {
Car pride= new Car();
}
}

۰۷ آذر ۹۴ ، ۲۳:۰۴ ۴ نظر موافقین ۱ مخالفین ۰
پریسا

Polymorphism یا چند ریختی

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

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

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

public class Parent {
public void printClassName(){
System.out.println("Parent");
}
}
public class Child extends Parent {
public void printClassName(){
System.out.println("Child");
}
}

public class Main {
public static void main(String[] args) {
Parent p= new Parent();
p.printClassName();

Child c= new Child();
c.printClassName();
}
}

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

Parent
Child

پس واضح است که وقتی یک متد override می شود زمانی که بر روی نمونه پدر صدا زده می شود متد پدر و زمانی که روی نمونه فرزند می شود صدا زده می شود متد مربوط به فرزند را اجرا می کند.

حال به مفهوم چند ریختی می پردازیم:

چند ریختی در شی گرایی

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

فرض می کنیم یک interface به نام Animal داریم که parent کلاس های مربوط به تمام حیوانات است. در این کلاس یک متد ()Speak داریم که صدای حیوانات را پرینت می کند:

public interface Animal {
void speak();
}

مطابق شکل سه حیوان مختلف داریم که از Animal ارث می برند و متد speak را override می کنند:

public class Dog implements Animal {

public void speak(){
System.out.println("Woof");
}
}
public class Cat implements Animal {
public void speak() {
System.out.println("Meow");
}
}
public class Duck implements Animal {
public void speak(){
System.out.println("Quack");
}
}

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

public class Main {
public static void main(String[] args) {

Animal animal1= new Cat();
Animal animal2= new Dog();
Animal animal3=new Duck();

animal1.speak();
animal2.speak();
animal3.speak();
}
}

خروجی :

Meow
Woof
Quack

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

۱۹ آبان ۹۴ ، ۲۱:۴۳ ۰ نظر موافقین ۱ مخالفین ۰
پریسا

Constructor یا سازنده 2

 پست قبل در مورد سازنده کلاس بود. در این پست به سازنده ها در جریان وراثت می پردازم. فرض می کنیم یک کلاس به نام Parent داریم به شکل زیر:

public class Parent {
public Parent()
{
...
}
}

حال فرض می کنیم این کلاس یک subclass به نام Child داشته باشد. همانطور که قبلا اشاره شد در زمان ساخت یک شی یا نمونه (Instance) از کلاس، متد سازنده ی آن فراخوانی می شود. اگر کلاسی فرزند کلاس دیگر باشد در این حالت باید بدانیم که در constructor آن باید constructor کلاس پدر نیز به نوعی فراخوانی شود. این کار از طریق استفاده از متد ()super انجام می شود. به شکل زیر:

public class Child extends Parent {
public Child(){
super();
...
}
}

حال فرض کنیم که constructor کلاس پدر argument هایی به عنوان ورودی دارد. در این حالت باید زمان نوشتن constructor برای فرزند پارامترهای ورودی constructor پدر را درون متد ()super بفرستیم:

public class Parent {
String name;
public Parent(String name)
{
....
}
}
public class Child extends Parent {
public Child(String name){
super(name);
...
}
}

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

public class Child extends Parent {
String name="Parisa";
public Child(){
super(name);
...
}
}

قبلا در پست مربوط به static گفت بودم که متغیر های غیر استاتیک متعلق به instance یا نمونه ی کلاس و متغیر های استاتیک متعلق به کلاس هستند. پس برای استفاده از متغییر های غیر استاتیک مانند متغیر name در کلاس Child باید حتما نمونه ای از کلاس Child ساخته شود و کد نوشته شده به شکل بالا دچار خطا می شود. پس با توجه به توضیحات داده شده متغیر name ر اباید بصورت static تعریف کنیم:

public class Child extends Parent {
static String name="Parisa";
public Child(){
super(name);
...
}
}
۱۲ مهر ۹۴ ، ۱۹:۰۲ ۰ نظر موافقین ۱ مخالفین ۰
پریسا