המשך תכנות
Download
1 / 35

המשך תכנות מונחה עצמים - PowerPoint PPT Presentation


  • 160 Views
  • Uploaded on

המשך תכנות מונחה עצמים. תרגול מס' 9. היום בתרגול. this Shallow Copy, Deep Copy ממשקים חריגות ( Exceptions ). תזכורת: מחלקות ואובייקטים. הנה המחלקה MyString :. public class MyString { //class fields private char [] elements ; private int length ; //class method

loader
I am the owner, or an agent authorized to act on behalf of the owner, of the copyrighted work described.
capcha
Download Presentation

PowerPoint Slideshow about ' המשך תכנות מונחה עצמים' - kendis


An Image/Link below is provided (as is) to download presentation

Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author.While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server.


- - - - - - - - - - - - - - - - - - - - - - - - - - E N D - - - - - - - - - - - - - - - - - - - - - - - - - -
Presentation Transcript

המשך תכנות מונחה עצמים

תרגול מס' 9


היום בתרגול

  • this

  • Shallow Copy, Deep Copy

  • ממשקים

  • חריגות (Exceptions)


תזכורת: מחלקות ואובייקטים

  • הנה המחלקה MyString:

publicclass MyString {

//class fields

private char[] elements;

private intlength;

//class method

publicint length(){

returnlength;

}

}

שדות – מייצגים מצב של האובייקט

שיטה – מתארת התנהגות של האובייקט


תזכורת: מחלקות ואובייקטים

  • על מנת ליצור אובייקט מסוג MyString, נשתמש במילה new:

  • אך כיצד ניתן לשים ערכים בתוך המחרוזת שלנו?

  • לשם כך נגדיר בנאי, שבעזרתו נאתחל את שדה האובייקט

MyString s = new MyString();


Constructor
תזכורת: בנאי (constructor)

  • בנאי – שיטה מיוחדת עבור מחלקה שתפקידה לייצר אובייקט ולאתחל את שדותיו

publicclass MyString {

//class fields

private char[] elements;

private intlength;

//constructor with a parameter

public MyString(char[] otherElements){

length = otherElements.length;

elements = newchar[length];

for (int i = 0; i < otherElements.length; i++) {

elements[i] = otherElements[i];

}

}

...

}

השם זהה לשם המחלקה ואין ערך החזרה


this

  • ראינו כי ניתן להגדיר מספר בנאים למחלקה בעזרת העמסה (Overloading)

  • ניתן לקרוא מבנאי אחד לבנאי אחר בעזרת המילה השמורה:

  • לדוגמה:

  • הקריאה חייבת להתבצע בשורה הראשונהשל הבנאי

this

public MyString(MyString other){

this(other.elements);

}

מה היתרון בשימוש בדרך זו?

( )


this

  • דוגמה נוספת: מה עושה הבנאי השני?

publicclass MyString{

privatechar[] elements;

privateint length;

public MyString(String s) {

}

public MyString() {

this("");

}

}


this

  • ניתן להשתמש ב - this על מנת להבדיל בין שדה לבין פרמטר או משתנה לוקאלי בעלי אותו שם. לדוגמה:

בעזרת האופרטור (.)

publicclass MyString{

private char[] elements;

private intlength;

public MyString(char[] elements, int length) {

this.length = length;

this.elements = newchar[this.length];

for (int i = 0; i < this.length; i=i+1)

this.elements[i] = elements[i];

}

}


תזכורת

  • תזכורת (מההרצאות) – המחלקות Point ו- Circle:

publicclass Point {

public doublex;

public doubley;

public Point() {

x = 0;

y = 0;

}

public Point(Point p) {

x = p.x;

y = p.y;

}

}

בנאי חסר פרמטרים

בנאי מעתיק


תזכורת

publicclass Circle{

public Point center;

public double radius;

//constructors

public Circle() {

center = new Point();

radius = 0;

}

public Circle(Point cen, double rad) {

center = new Point(cen);

if (rad >= 0)

radius = rad;

else

rad = 0;

}

}//Circle

בנאי חסר פרמטרים

בנאי המקבל את כל השדות


Deep copy shallow copy
Deep Copy ו- Shallow Copy

  • בנאי מעתיק אפשרי ל- Circle:

  • מה יקרה אם נבצע את הפעולות הבאות:

  • הבנאי המעתיק משתמש בגישת ה- Shallow Copy.

public Circle(Circle other) {

center = other.center;

radius = other.radius;

}

Copy constructor

publicstaticvoid main(String[] args){

Circle circ1 = new Circle();

Circle circ2 = new Circle(circ1);

circ2.center.x = 4;

}


Deep copy shallow copy1
Deep Copy ו- Shallow Copy

  • בנאי מעתיק אפשרי ל- Circle:

  • מה יקרה עכשיו אם נבצע את הפעולות הבאות:

  • הבנאי המעתיק משתמש בגישת ה- Deep Copy.

public Circle(Circle other) {

center = new Point(other.center);

radius = other.radius;

}

publicstaticvoid main(String[] args){

Circle circ1 = new Circle();

Circle circ2 = new Circle(circ1);

circ2.center.x = 4;

}


ממשקים

  • ממשק מייצג רעיון מופשט.

  • הממשק (interface) הינו כלי ב-Java למימוש עיקרון ההפרדה בין הכרזה למימוש.

  • מבחינת המתכנת, ממשק הוא הצהרת כוונות או הבטחה שצריך למלא. ממשק קובע את הפונקציונאליות המשותפת לכל המחלקות המממשות אותו.

אוניברסיטת בן גוריון - מבוא למדעי המחשב


ממשקים – כללים בסיסיים

הצהרה על ממשק:

publicinterface<name> {

<methods list>

}

  • ממשקים מתארים שיטות (ציבוריות) ללא ישומן.

  • כל השיטות בממשק הן ציבוריות (public) - גם אם לא הוגדרו כך במפורש

  • הגדרת שיטה כפרטית בממשק היא טעות קומפילציה.

    הערה חשובה: המשתמש במחלקה המממשת ממשק אינו יכול לדעת את פרטי המימוש של השיטות, ואפילו רצוי שלא יצטרך לחשוב עליהם כדי שיוכל להתרכז במשימה שלפניו ולטפל בה ברמת מופשטות מתאימה.


ממשקים – כללים בסיסיים

לדוגמה:

publicinterfacePredator {

publicboolean chasePrey(Prey p);

publicvoid eatPrey(Prey p);

}

  • ממשקים מתארים שיטות (ציבוריות) ללא ישומן.

  • כל השיטות בממשק הן ציבוריות (public) - גם אם לא הוגדרו כך במפורש

  • הגדרת שיטה כפרטית בממשק תגרום לטעות קומפילציה.


ממשקים – כללים בסיסיים

  • ממשק, בדומה למחלקה, מגדיר טיפוס.שדות, משתנים ופרמטרים יכולים להיות מוגדרים להיות מסוג ממשק.למשל, ניתן להצהיר על משתנהx להיות מסוג Predator:

    Predator x;

  • לא ניתן ליצור אובייקט מממשק. למשל:

    x = new Predator();

// will not compile !!!


ממשקים – כללים בסיסיים

  • ניתן להצהיר על מחלקה כמימוש של ממשק כך:

    class Tiger implements Predator

  • מחלקה כזו צריכה לממש את כל שיטות הממשק (שגיאת קומפילציה). יוצאות מן הכלל הזה הן מחלקות אבסטרקטיות, עליהן נדבר בהמשך הקורס.

  • מחלקה יכולה לממש יותר מממשק אחד! – נראה דוגמה בהמשך


publicinterfacePredator {

public boolean chasePrey(Prey p);

public void eatPrey(Prey p);

}

publicclassTigerimplementsPredator {

publicboolean chasePrey(Prey p) {

// code to chase prey p (specifically for a tiger)

return runAfterPrey(p);

}

publicvoid eatPrey (Prey p) {

// code to eat prey p (for a tiger)

chew(p);

swallow(p);

}

...

}


publicinterfacePredator {

public boolean chasePrey(Prey p);

public void eatPrey(Prey p);

}

publicclassSharkimplementsPredator {

publicboolean chasePrey(Prey p) {

// code to chase prey p (specifically for a shark)

return swimAfterPrey(p);

}

publicvoid eatPrey (Prey p) {

// code to eat prey p //(specifically for a shark)

bite(p);

swallow(p);

}

}


  • "טרף" הוא גם כן תאור כללי של יצור, המסוגל לבצע מספר פעולות בסיסיות. גם לו יהיה ממשק:

    publicinterfacePrey {

    publicboolean isAlive();

    publicvoid die();

    publicvoid runAway();

    }

  • דוגמאות למחלקות שעשויות לממש "טרף":

    publicclassFrogimplementsPrey {

    publicvoid jump() { ... }

    publicvoid runAway() { ... }

    ...

    }

    publicclassDeerimplementsPrey {

    ...

    }


  • כריש הוא טורף וגם נמר הוא טורף. המסוגל לבצע מספר פעולות בסיסיות. גם לו יהיה ממשק:

  • בזכות הממשק המשותף אותו הם ממשים, אנחנו יכולים למשל, להחזיק מערך של טורפים ולהפעיל פעולות משותפות על כל אחד מהאיברים במערך.

    Predator[] preds = new Predator[3];

    preds[0] = new Tiger();

    preds[1] = new Shark();

    preds[2] = new Shark();

    Prey froggy = new Frog();

    for (int i=0; i<preds.length && froggy.isAlive(); i=i+1) {

    froggy.runAway();

    if (preds[i].chasePrey(froggy))

    preds[i].eatPrey(froggy);

    }

  • ניתן לראות שיצרנו גם טרף – צפרדע, שנרדף ע"י הכרישים והנמר. מיד נראה מה טרף מסוגל לבצע, כלומר כיצד הוגדר ממשק של טרף – interface Prey.

האם ניתן היה להפעיל:

froggy.jump()

?


  • אך קודם נראה דוגמה כיצד ניתן לקבל טורף וטרף כפרמטר לפונקציה:

    publicstaticvoidsimulateChase(Predator predat, Prey prey) {

    prey.runAway();

    if (predat.chasePrey(prey))

    predat.eatPrey(prey);

    }

  • אנחנו יכולים להפעיל את הפעולות שטורף וטרף יודעים לעשות, למרות שאיננו יודעים איזה טורף או טרף קיבלנו בקריאה לפונקציה.


המשך טורף וטרף כפרמטר לפונקציה:

Shark sharky1 = new Shark();

Frog kermit1 = new Frog();

simulateChase(sharky1, kermit1);

שימו לב, ניתן גם לרשום:

Predator sharky2 = new Shark();

Prey kermit2 = new Frog();

simulateChase(sharky2, kermit2);

•טיפוס המשתנה (reference type) קובע אילו שיטות חוקיות לביצוע עבור המשתנה (נבדק בזמן הידור).

•טיפוס האובייקט ((instance type בזיכרון שעליו מצביע המשתנה בזמן הריצה קובע איזו שיטה תופעל (כלומר, מאיזו מחלקה מממשת).


  • ניתן, כמובן, להוסיף פעולות (שיטות) ומצב (שדות) למחלקות השונות, ללא קשר לממשק אותן ממשות. לדוגמה:

    publicclassSharkimplementsPredator {

    private String name;

    privateintnumOfTeeth;

    public Shark(String name) {

    this.name = name;

    numOfTeeth = 3000 + (int)(Math.random()*1000);

    }

    privatevoidswallow(Prey p) {

    p.die();

    }

    publicintgetNumOfTeeth() { returnnumOfTeeth; }

    publicvoidswimForFun() { ... }

    publicvoid eatPrey (Prey p) {

    bite(p);

    swallow(p);

    }

    ...

    }


מימוש מספר ממשקים ומצב (שדות) למחלקות השונות, ללא קשר לממשק אותן ממשות. לדוגמה:

  • ניתן לממש יותר מממשק אחד.

  • על המחלקה המיישמת לממש את הפונקציות של כל הממשקים.

  • אם מחלקה מיישמת שני ממשקים בעלי שיטה בעלת שם זהה נניח foo אז:

  • אם לשתי ה foo יש חתימה שונה אז המחלקה המיישמת חייבת לממש את שתיהן.

  • אם לשתי ה foo יש אותה חתימה ואותו טיפוס מוחזר אז המחלקה מיישמת רק foo אחד.

  • אם לשתי ה foo יש אותה חתימה אך טיפוס מוחזר שונה - טעות קומפילציה. (לא ניתן לממש את שני הממשקים יחד).

  • עד עתה חשבנו על צפרדע כטרף. אבל ניתן לחשוב עליו גם כטורף (זבובים יהיו הטרף שלו במקרה זה)

    publicclassFrogimplementsPrey, Predator {

    publicboolean chasePrey(Prey p) {

    ...

    }

    publicvoid eatPrey (Prey p) {

    ...

    }

    ...

    }


לא ומצב (שדות) למחלקות השונות, ללא קשר לממשק אותן ממשות. לדוגמה:

לא

כן

האם ניתן היה להגדיר את sharky כ-Predator?

האם ניתן היה להגדיר את kermit כ-Prey?

האם ניתן היה להגדיר את bzzit כ-Prey?

כעת הצפרדע יכולה לבצע את שני התפקידים:

Shark sharky = new Shark();

Frog kermit = new Frog();

Fly bzzit = new Fly();

simulateChase(sharky, kermit);

if(kermit.isAlive())

simulateChase(kermit, bzzit);

sharky.swimForFun();

הערה: אף צפרדע (או זבוב) לא נפגע בהכנת התרגול


Exceptions
חריגות ( ומצב (שדות) למחלקות השונות, ללא קשר לממשק אותן ממשות. לדוגמה:Exceptions)

חריגה היא אירוע המתרחש במהלך תוכנית המפר את תהליך הריצה הנורמאלי של פקודות התוכנית

לעיתים חריגות מתרחשות בגלל תקלות בלתי צפויות, כגון בעיה בקובץ אליו כותבים (למשל אין הרשאות כתיבה), ולעיתים בגלל תקלות תוכנה, כגון שליחת פרמטר לא מתאים לפונקציה


Exceptions1
בעצם כבר נתקלנו ב- ומצב (שדות) למחלקות השונות, ללא קשר לממשק אותן ממשות. לדוגמה:Exceptions

Runtime Exceptions

IndexOutOfBoundsException: חריגה ממערך

NullPointerException:

ניסיון לפעול על משתנה שאינו פרימיטיבי בעל ערך null


Throw exceptions
Throw Exceptions ומצב (שדות) למחלקות השונות, ללא קשר לממשק אותן ממשות. לדוגמה:

publicvoid setChar(int index, char ch) {

if (this.length <= index || index < 0) {

thrownew RuntimeException("Index out of bound");

} else {

this.elements[index] = ch;

}

}

publicstaticvoid main(String[] args) {

MyStringstr = newMyString("Hello world");

str.setChar(-1, '!');

}

Exception in thread "main" java.lang.RuntimeException: Index out of bound

at MyString.setChar(MyString.java:26)

at Main.main(Main.java:35)


Runtimeexceptions
כבר נתקלנו ב- ומצב (שדות) למחלקות השונות, ללא קשר לממשק אותן ממשות. לדוגמה:RuntimeExceptions

וראינו כי ניתן לזרוק RuntimeException באמצעות throw

ArithmeticException:

ניסיון חלוקה באפס

IndexOutOfBoundsException: חריגה ממערך

NullPointerException:

ניסיון לפעול על משתנה שאינו פרימיטיבי בעל ערך null


Throw runtimeexception
Throw ומצב (שדות) למחלקות השונות, ללא קשר לממשק אותן ממשות. לדוגמה:RuntimeException

publicclass Car {

privatefinalint MAX_SPEED = 210;

privatefinalint MIN_SPEED = -20;

privateint speed;

publicvoidsetSpeed(int speed){

if ((speed >= MIN_SPEED) && (speed <= MAX_SPEED))

this.speed= speed;

else

thrownewRuntimeException(“Illegal speed”);

}

}

publicstaticvoid main(String[] args) {

Car car = new Car();

car.setSpeed(300);

}

Output: Exception in thread "main" java.lang.RuntimeException: Illegal Speed

at Car.setSpeed(Car.java:11)

at Car.main(Car.java:17)


Exceptions2
סוגי ומצב (שדות) למחלקות השונות, ללא קשר לממשק אותן ממשות. לדוגמה:Exceptions

Object

Exception

IOException

RuntimeException

NullPointerException


Exception
Exception ומצב (שדות) למחלקות השונות, ללא קשר לממשק אותן ממשות. לדוגמה:

  • ניתן לייצר חריגהע"י פקודת throwהמייצרת את אירוע החריגה.

  • ישנן שתי דרכים לטפל בחריגה:

    • לתפוס את ה- Exception על ידי שימוש במילים השמורות tryו-catch

    • להעביר את ה- Exception הלאה על ידי שימוש במילה השמורה throwsבכותרת הפונקציה שאנו כותבים.

      (טיפול בחריגות לא הכרחי עבור (RuntimeExceptions


Throw and catch exceptions
Throw and Catch Exceptions ומצב (שדות) למחלקות השונות, ללא קשר לממשק אותן ממשות. לדוגמה:

publicclass Car {

privatefinalint MAX_SPEED = 210;

privatefinalint MIN_SPEED = -20;

privateint speed;

publicvoidsetSpeed(int speed) throws Exception {

if ((speed >= MIN_SPEED) && (speed <= MAX_SPEED))

this.speed = speed;

else

thrownew Exception(“Illegal speed”);

}

}

publicstaticvoid main(String[] args) {

Car car = new Car();

car.setSpeed(100);

}

Compilation Error


Throw and catch exceptions1
Throw and Catch Exceptions ומצב (שדות) למחלקות השונות, ללא קשר לממשק אותן ממשות. לדוגמה:

publicclass Car {

privatefinalint MAX_SPEED = 210;

privatefinalint MIN_SPEED = -20;

privateint speed;

publicvoidsetSpeed(int speed) throws Exception {

if ((speed >= MIN_SPEED) && (speed <= MAX_SPEED))

this.speed = speed;

else

thrownew Exception(“Illegal speed”);

}

}

publicstaticvoid main(String[] args) {

Car car = new Car();

try{

car.setSpeed(300);

System.out.println("Broke the speed limit !");

} catch(Exception e){

System.err.println("Caught Exception: "+e.getMessage());

}

System.out.println("Current speed is "+car.getSpeed()+” km/h);

}

Output: Caught Exception: Illegal Speed

Current speed is 0 km/h


ad