Download presentation
Presentation is loading. Please wait.
1
مظفر بگ محمدی دانشگاه ایلام
ترکیب مظفر بگ محمدی دانشگاه ایلام
2
استفاده مجدد از کد توسعه ی موثر نرم افزار بر مینای استفاده ی مجدد از کد قرار دارد. استفاده ی مجدد از کد به معنای کپی کردن و تغییر آن نیست. کاری که در زبانهای رویه ای مثل C متداول است. هدف OOP استفاده ی مجدد از کلاسها بدون تغییر کد کلاس است. یکی از تکنیکهای OOP در جهت استفاده ی مجدد از کد ترکیب نام دارد.
3
یک پایگاه داده ساده یکی از دوستان شما می خواهد پایگاه داده ای از اعضای فامیل تهیه نماید. او می خواهد که نام، تاریخ تولد و روز وفات هر کدام از اعضای فامیل را ثبت کند. لازم است که اطلاعات تمام اعضای فامیل طی گزارشی چاپ شود. برای اینکار باید بتوان اعضای فامیل را با هم مقایسه کرد تا از ردیفهای تکراری پایگاه داده اجتناب شود. همچنین به منظور تسهیل ورود اطلاعات، لازم است که بتوان از یک عضو فعلی فامیل کپی گرفت. برای این پروژه یک کلاس به اسم Person درست و پیاده می کنیم که برای تمایش هر عضو فامیل بکار می رود.
4
طراحی کلاس Person :رفتار و خدمات
5
طراحی کلاس Person : خواص
خواص کلاس Person شامل یک متغییر رشته به اسم name، و دو تمتغییر از نوع Date به اسامی born و died است. تمام خواص از متغییرهای نوع کلاس هستند. به منظور تامین امنیت، تمام خواص از نوع private تعریف می شوند. public class Person { private String name; private Date born; private Date died; //null means still alive . . . 5
6
طراحی کلاس Person : شرایط
هر شخص حداقل باید دارای اسم و تاریخ تولد باشد. لذا وجود جز سازنده بدون آرگومان بی معنی است. شخصی که هنوز زنده است، نباید تاریخ وفات آن تنظیم شده باشد. یعنی مقدار died باید برابر null باشد. شخصی که مرده است، باید تاریخ تولد آن قبل از تاریخ وفاتش باشد. یعنی اگر هر دو تاریخ داده شوند، باید این موضوع چک شود. 6
7
طراحی کلاس Person : invariant
عبارتی که در مورد تمام اشیا کلاس همواره صحیح است تحت عنوان قسمت تغییر ناپذیر کلاس شناخته می شود. با استفاده از قسمت تغییر ناپذیر کلاس می توان کلاس را بصورت سازگار و منسجم تعریف نمود. در مورد کلاس Person موارد زیر همیشه صحیح هستند: هر شی از نوع کلاس Person حتما دارای اسم و تاریخ تولد است و اگر دارای تاریخ وفات باشد، مقدار آن برابر یا تازه تر از تاریخ تولد است. اگر کلاس Person را چک کنیم، برای هر شی که توسط جز سازنده ایجاد شده باشد؛ خاصیت فوق برقرار است و تمام متدهای دیگر نیز درستی این عبارت را رعایت و حفظ می کنند. 7
8
خلاصه ی قسمت تغییر ناپذیر کلاس
قسمت تغییرناپذیر کلاس به عنوان جزیی از مستندات کلاس بیان می گردد. کنترل خطا در سازنده ها و تغییر دهنده ها باعث می شود که قسمت تغییر ناپذیر کلاس مخدوش نشود. متدهایی که حالت کلاس را عوض نمی کنند، می توانند فرض کنند که خواص تغییرناپذیر کلاس نقض نشده اند.
9
A Person Class Constructor
public Person( String theName, Date birthDate, Date deathDate ) { // check that birthDate <= deathDate // consistent( ) is a private helper method if ( theName != null && consistent(birthDate, deathDate)) name = theName; born = new Date( birthDate ); // copy the birtheDate object if( deathDate == null ) died = null; else died = new Date( deathDate ); } // later we’ll deal with errors differently System.out.println( "Inconsistent Person parameters.“ ); System.exit( 0 ); Note that name does not make a copy of theName in the same way that born makes a copy of birthDate This is possible because Java Strings are immutable, so it’s ok that multiple references share the same String object 9
10
Designing a Person Class: The Class Invariant
/** Class invariant: A Person always has a date of birth, and if the Person has a date of death, then the date of death is equal to or later than the date of birth. To be consistent, name and birthDate must not be null. If there is no date of death (deathDate == null), that is consistent with any birthDate. Otherwise, the birthDate must come before or be equal to the deathDate. precedes() is a boolean method in Date */ private boolean consistent(Date birthDate, Date deathDate) { if( birthDate == null ) return false; if( deathDate == null ) return true; return birthDate.precedes( deathDate ) || birthDate.equals( deathDate ); } 10
11
ترکیب کلاس Person سه خاصیت دارد:
private String name; private Date born; private Date died; استفاده از کلاسها بعنوان خاصیت یک کلاس دیگر تحت عنوان تجمیع یا ترکیب شناخته می شود. ترکیب یک راه اساسی برای استفاده ی مجدد از کد است. اما باید بعضی ملاحظات را نیز رعایت کرد.
12
ملاحظات ترکیب در حالت ترکیب، Person از کلاسهای Date و String استفاده می نماید. کلاس Person دارای هیچ گونه امتیازی نسبت به کلاسهای Date و String نیست. کلاس Person باید پاسخگویی را در مواقع لزوم به کلاسهای Date و String بسپارد.
13
طراحی کلاس Person : متد equals
در تعریف equals از کلاس Person، متدهای equals از کلاسهای String و Date فراخوانی شد. یعنی کلاس Person وظیفه ی پاسخ به سوال تساوی را از طریق فراخوانی equals به کلاسهای String و Date می سپارد. جاوا مشخص می کند که کدام متد equals از کدام کلاس فراخوانی شود. 13
14
طراحی کلاس Person : متد equals
public boolean equals(Person otherPerson) { if (otherPerson == null) return false; else return name.equals(otherPerson.name) && born.equals(otherPerson.born) && datesMatch(died, otherPerson.died); } This is the equals method for the String class This is the equals method for the Date class This is a special helper method that handles null Date references 14
15
طراحی کلاس Person : متد کمکی DatesMatch
/** To match date1 and date2 must either be the same date or both be null. */ private boolean datesMatch( Date date1, Date date2 ) { if( date1 == null ) return date2 == null; // both null is ok else if( date2 == null ) // && date1 != null return false; // only one null not ok else // both dates are not null return date1.equals( date2 ); } 15
16
طراحی کلاس Person : متد toString
متد toString از کلاس Person متد toString را از کلاس Date فراخوانی می کند. مثالی دوباره از استفاده ی مجدد از کد و واگذاری وظیفه به دیگران یا همان استفاده از ترکیب public String toString( ) { String diedString; if( died == null ) diedString = ""; //Empty string else diedString = died.toString( ); return name + ", " + born.toString + "-" + diedString; } 16
17
طراحی کلاس Person : نسخه برداری
گرفتن کپی از یک شی مستلزم وجود متد خاصی به اسم سازنده ی کپی است. سازنده ی کپی نوعی سازنده است که یک آرگومان از نوع خود کلاس دارد. سازنده ی کپی باید یک شی جدا ایجاد کند که خواص آن کپی شی اصلی (آرگومان متد) باشد.
18
سازنده ی کپی برای کلاس Date
// a class that does not use composition can // simply copy the values of the primitive instance // variables public Date( Date aDate ) { if( aDate == null ) // Not a real date object parameter // we’ll handle errors differently later System.out.println( "Fatal Error.“ ); System.exit( 0 ); } // just copy the primitive variables using assignment // month is a String which is NOT primitive, but that’s ok month = aDate.month; day = aDate.day; year = aDate.year; 18
19
استفاده از ترکیب در سازنده ی کپی
بدلیل ترکیب، استفاده از روش اسلاید قبلی (سازنده ی Date) در مورد Person درست کار نخواهد کرد. public Person( Person original ) { if( original == null ) System.out.println( "Fatal error.“ ); System.exit( 0 ); } name = original.name; // ok born = original.born //dangerous died = original.died //dangerous این کد یک نسخه ی مستقل از شی original تولید نخواهد کرد. 19
20
سازنده ی کپی برای کلاس Person
روش درست نوشتن کد سازنده ی کپی برای کلاس Person این است که برای اشیاء born و date یک کپی مستقل و جدید از شی original (از نوع Person) ایجاد کنیم. born = new Date( original.born ); دقت کنید که این روش نیاز دارد که در صورت استفاده از ترکیب - یعنی وجود متغییر های از نوع کلاس - آن متغییرها (مثلاً Date) نیز خود دارای جزء سازنده باشند. 20
21
سازنده ی کپی برای کلاس Person
public Person( Person original ) { if( original == null ) System.out.println( "Fatal error.“ ); System.exit( 0 ); } name = original.name; born = new Date( original.born ); if( original.died == null ) died = null; else died = new Date( original.died ); Name = new String( original.name) is unnecessay because Strings are immutable 21
22
استفاده و سوءاستفاده از ارجاع
هنگام نوشتن برنامه، لازم است که متغییرهای خصوصی واقعاً خصوصی باقی بمانند. در مورد متغییرهای اصلی، اضافه کردن کلمه ی private کافی است. در مورد متغییرهای از نوع کلاس، مشکل فقط با اضافه کردن کلمه ی private حل نمی شود. 22
23
نشت محرمانگی در مورد کلاس Person، دیدیم که پیاده سازی جزء سازنده می تواند مشکل آفرین باشد. مشکل مشابهی در هنگام نوشتن متدهای get و set برای متغییرهای کلاس می تواند اتفاق بیفتد: غلط public Date getBirthDate( ) { return born; //dangerous – why?? } درست return new Date( born ); //correct 23
24
ترکیب و کپسوله سازی فرض کنید که کاربر کلاس Person بخواهد که فقط سه حرف اول ماه تولد نمایش داده شود. چگونه می توان این مساله را با رعایت اصول کپسوله سازی حل کرد.
25
راه حل اول یک متد دسترسی برای شی born به اسم getBornDate و یک متد دسترسی برای شی monthبه اسم getMonth بنویسید. کاربر کلاس Person می تواند کد زیر را بنویسد: Person bob = new Person(“Bob”, new Date(“January”, 14, 1944), null); String abbrev = bob.getBornDate( ).getMonth().substring(0,2); System.out.println( abbrev ); مزایا و معایب این روش چیست؟
26
راه حل دوم به کلاس Date یک متد جدید اضافه کنید که خلاصه ی 3 حرفی ماه را برگرداند. public String getMonthAbbreviation( ) { return month.substring(0, 2); } به کلاس Personیک متد جدید اضافه کنید که خلاصه ی 3 حرفی ماه را از شی born بگیرد و به کاربر برگرداند. public String getBornAbbreviation( ) { return born.getMonthAbbreviation(); } حال کاربر کلاس Person می تواند کد زیر را بنویسد: Person bob = new Person(“Bob”, new Date(“January”, 14, 1944), null); String abbrev = bob.getBornAbbreviation(); System.out.println( abbrev ); مزایا و معایب این روش چیست؟
27
private double[ ] grades;
ترکیب و آرایه ها همانطور که یک کلاس می تواند به عنوان متغییر یک کلاس دیگر تعریف شود، آرایه ها هم می توانند در داخل کلاس به عنوان متغییر تعریف شوند. می توانیم یک آرایه از نوع اصلی تعریف کنیم: private double[ ] grades; یا می توانیم یک آرایه از نوع کلاس تعریف کنیم: private Date [ ] dates;
28
نشت محرمانگی در متغییرهای آرایه ای
اگر یک متد دسترسی برای آرایه بنویسیم، باید مواظب آدرس ارجاع اشیاء خصوصی باشیم. public double[ ] getGrades( ) { return grades; } مثال بالا منجر به نشت محرمانگی می شود. 28
29
نشت محرمانگی در متغییرهای آرایه ای
مثال قبلی یک متغییر ارجاع به خود آرایه ی grade بر می گرداند. درست این است که متد دسترسی یک کپی عمیق از آرایه ی grade را برگرداند. در زیر کد صحیح متد getGrades مشاهده می شود: public double[ ] getGrades( ) { double[ ] temp = new double[ grades.length ]; for( int i = 0; i < grades.length; i++ ) temp[ i ] = grades[ i ]; return temp; } 29
30
نشت محرمانگی در متغییرهای آرایه ای
اگر متغییر خصوصی آرایه ای از متغییرهای نوع کلاس است، باید از هر کدام از اشیاء آرایه جداگانه کپی گرفت. public Date[ ] getDates( ) { Date[ ] temp = new Date[ dates.length ]; for( int i = 0; i < dates.length; i++ ) temp[ i ] = new Date( dates[ i ] ); return temp; } 30
Similar presentations
© 2024 SlidePlayer.com. Inc.
All rights reserved.