1 / 45

תרגול 11

תרגול 11. המשך תכנות מונחה עצמים. היום בתרגול. פולימורפיזם כללי הרשאות בהורשה מחלקות אבסטרקטיות. פולימורפיזם (רב צורתיות). התייחסות לעצמים שונים (instance) כדברים דומים (reference) בעלי מכנה משותף.

dacey-buck
Download Presentation

תרגול 11

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. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. תרגול 11 המשך תכנות מונחה עצמים

  2. היום בתרגול • פולימורפיזם • כללי הרשאות בהורשה • מחלקות אבסטרקטיות

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

  4. publicclass Book { private String name; privateintpages; public Book(String name, int p){ this.name = new String(name); this.pages = p; } public String getName(){ returnthis.name; } publicvoid message() { System.out.println(this.name +": " + this.pages + " pages"); } }

  5. /* A Dictionary is a kind of Book with definitions */ publicclass Dictionary extends Book { privateintdefinitions; public Dictionary(String name, int pages, intdefs) { super(name, pages); this.definitions = defs; } publicvoid message() { System.out.println(getName() + ": " + definitions + " definitions"); } publicintgetDefinitions(){ returnthis.definitions; } }

  6. /* A Cook Book is a kind of Book with recipes */ publicclass Cookbook extends Book { privateintrecipes; public Cookbook(String name, int pages, int recipes) { super(name, pages); this.recipes = recipes ; } publicvoid message() { System.out.println(getName() + ": " + this.recipes + " recipes "); } }

  7. שימוש בפולימורפיזם • התייחסות לספרים שונים באופן אחיד לפי יכולות מחלקת האב: publicstaticvoid main(String[] args) { Book [] books = new Book[3]; // new above is for the array not Book objects books[0] = new Dictionary("Webster“, 690, 45056); books[1] = new Cookbook("Naked Chef“, 100, 50); books[2] = new Book("War and Peace“, 1000); for (inti=0; i<books.length; i=i+1) books[i].message(); } books Output Webster: 45056 definitions Naked Chef: 50 recipes War and Peace: 1000 pages

  8. שימוש בפולימורפיזם • התייחסות לספרים שונים באופן אחיד לפי יכולות מחלקת האב: publicstaticvoid main(String[] args) { Book [] books = new Book[3]; // new above is for the array not Book objects books[0] = new Dictionary("Webster“, 690, 45056); books[1] = new Cookbook("Naked Chef“, 100, 50); books[2] = new Book("War and Peace“, 1000); books[0].getDefinitions(); // what would this line do ? } books // compilation error - no getDefinitions() for Book בעזרת Casting איך ניתן בכל זאת להפעיל שיטה ספציפית? ((Dictionary)books[0]).getDefinitions(); שימו לב: תכנון נכון של המחלקות יכלול דריסת פונקציותבמקום Casting

  9. פולימורפיזם הינו "חד-כיווני" • משתנה מטיפוס Cookbook לא יכול להכיל אובייקט מטיפוס Book. (כי טיפוס מחלקת האב הוא כללי יותר) השורה: Cookbook deserts = newBook() תיתן שגיאת קומפילציה

  10. כללי הרשאות (visibility modifiers) בהורשה public– שדות ושיטות המוגדרים כ-public ניתנים לגישה מתוך ומחוץ למחלקה. protected– שדות ושיטות המוגדרים כ-protected ניתן לגישה מתוך המחלקה וממחלקות היורשות מהמחלקה אך אינם ניתן לגישה ממחלקות אחרות *. (* ממחלקות אחרות הנמצאות ב package אחר. protected מתנהג כמו public באותו package) private – שדות ושיטות המוגדרים כ-private אינם ניתנים לגישה מחוץ למחלקה. ניסיון לגשת לשדה או שיטה כזו מחוץ למחלקה יעורר שגיאת קומפילציה.

  11. כללי הרשאות (visibility modifiers) בהורשה • שיטות לא יכולות להידרס ע"י שיטה מרמת שיתוף נמוכה יותר, זו שגיאת קומפילציה. כלומר: • לא ניתן לדרוס שיטה public עם protected או private • לא ניתן לדרוס שיטה protected עם שיטה private class Book { public String getName() { … } } class Dictionary extends Book { protected String getName() { … } } Compilation Error שאלה: מה ההיגיון מאחורי שגיאה זו? Book b = new Dictionary(); S.O.P(b.getName());

  12. כללי הרשאות (visibility modifiers) בהורשה • משתנים אינם עוברים דריסה בהורשה. • שיטות שאינן private עוברות בהורשה. • נועדו למימוש פנימי של מחלקת האב, ואינם ניתנים לשימוש ע"י תת מחלקה. • תת-המחלקה לא מכירה את המשתנים והשיטות הפרטיות של המחלקת האב, ממנה היא יורשת, ולכן עשויה גם להכריז על משתנים ושיטות פרטיות בעלי אותו שם וחתימה. • דוגמה: • חנות היא סוג של עסק • עסק: דמי שכירות, עובדים, הוצאות חודשיות • חנות: פריטי סחורה, הוצאות חודשיות הכוללות אחזקת מלאי. • כל אחד מהם מומש ע"י מתכנת אחר • בכל אחד מימוש שונה לשיטה פרטית - calcSum()

  13. publicclass Business { protected Employee[] employees; protecteddoublemonthlyRent; ...... // calculates total monthly expenses publicdouble monthlyExpenses() { double salaries = calcSum(); returnthis.monthlyRent + salaries; } // calculates monthly salaries privatedouble calcSum() { double sum = 0; for (int i=0; i<this.employees.length; i=i+1) sum = sum + this.employees[i].getSalary(); return sum; } ...... }  קריאה לשיטה פרטית

  14. public class Shop extends Business { protected Item[] items; ...... // override: calculates total monthly expenses publicdouble monthlyExpenses() { double itemPrices = calcSum(); return itemPrices + super.monthlyExpenses(); } // No override: calculates total item prices privatedouble calcSum() { double sum=0; for (int i=0; i<this.items.length; i=i+1){ sum = sum + this.items[i].getPrice(); } return sum; } ...... }  קריאה לשיטה פרטית שאלה: אם נשנה את המאפיין של calcSum ל-protected מה תחשב monthlyExpenses?

  15. סיכום חוקי גישה לשיטות ושדות בהורשה ב Java: • טיפוס המשתנה (טיפוס המצביע/ reference type) קובע בזמן הידור אילו שיטות ניתן להפעיל על המשתנה ולאילו שדות של המשתנה ניתן לגשת. • בקריאה לשיטה שאינה פרטית המופיעה במחלקת-אב ובתת-מחלקה, אם ע"י קריאה ישירה או ע"י שימוש באופרטור השייכות (.), הקוד המופעל נקבע בהתאם למחלקת האובייקט בפועלinstance type) ) שעליו מופעלת השיטה (ומשם בסריקה מלמטה למעלה לפי היררכית ההורשה). • שיטה פרטית נגישה רק בתוך ה- scope של המחלקה בה היא מוגדרת. בקריאה לשיטה פרטית, הקוד המופעל נקבע לפי ה -scope בו ממוקמת הקריאה. • בגישה לשדה (קריאה או השמה), ע"י גישה ישירה (ללא אופרטור השייכות), הגישה לשדה נקבעת לפי ה-scope בה ממוקמת הגישה (ומשם בסריקה מלמטה למעלה לפי היררכית ההורשה). • בגישה לשדה (קריאה או השמה) שאינו פרטי, ע"י אופרטור השייכות, בהתאם למחלקת טיפוס המשתנהreference type) ) שעליו מופעלת השיטה (ושם בסריקה מלמטה למעלה לפי היררכית ההורשה).

  16. דוגמה להורשה (שאלה ממבחן)

  17. publicclass A { privateintx; publicinty; public A(int x) { this.x = x; this.y = 2*x; } publicintgetX() { returnx; } publicintdoubleX() { return 2 * getX(); } publicinttripleX() { return 3 * x; } privateintsubXhelper() { returnx - 1; } publicintsubX() { returnsubXhelper(); } } publicclass B extends A { privateintx; publicinty; public B(intxA, intxB) { super(xA); this.x = xB; this.y = xA + xB; } publicintgetX() { returnx; } publicintsuperX() { returnsuper.getX(); } publicinttenTimesX() { return 10*x; } privateintsubXhelper() { returnx-2; } } A a = new A (1); A b = new B (2, 22); Output / Notes System.out.println(a.getX()); System.out.println(b.getX()); System.out.println(b.superX()); 1 22 Compilation Error !! if (b instanceof B) System.out.println(b.superX()); Compilation Error !!

  18. publicclass A { privateintx; publicinty; public A(int x) { this.x = x; this.y = 2*x; } publicintgetX() { returnx; } publicintdoubleX() { return 2 * getX(); } publicinttripleX() { return 3 * x; } privateintsubXhelper() { returnx - 1; } publicintsubX() { returnsubXhelper(); } } publicclass B extends A { privateintx; publicinty; public B(intxA, intxB) { super(xA); this.x = xB; this.y = xA + xB; } publicintgetX() { returnx; } publicintsuperX() { returnsuper.getX(); } publicinttenTimesX() { return 10*x; } privateintsubXhelper() { returnx-2; } } A a = new A (1); A b = new B (2, 22); Output / Notes B bb = (B)b; System.out.println(bb.superX()); 2 System.out.println(((B)b).superX()); 2 System.out.println(a.tripleX()); System.out.println(b.tripleX()); 3 6

  19. publicclass A { privateintx; publicinty; public A(int x) { this.x = x; this.y = 2*x; } publicintgetX() { returnx; } publicintdoubleX() { return 2 * getX(); } publicinttripleX() { return 3 * x; } privateintsubXhelper() { returnx - 1; } publicintsubX() { returnsubXhelper(); } } publicclass B extends A { privateintx; publicinty; public B(intxA, intxB) { super(xA); this.x = xB; this.y = xA + xB; } publicintgetX() { returnx; } publicintsuperX() { returnsuper.getX(); } publicinttenTimesX() { return 10*x; } privateintsubXhelper() { returnx-2; } } A a = new A (1); A b = new B (2, 22); Output / Notes Run-time Error: ClassCastException: A cannot be cast to B System.out.println(((B)a).tenTimesX()); System.out.println(((B)b).tenTimesX()); System.out.println(b.doubleX()); 220 44 System.out.println(b.subX()); 1

  20. publicclass A { privateintx; publicinty; public A(int x) { this.x = x; this.y = 2*x; } publicintgetX() { returnx; } publicintdoubleX() { return 2 * getX(); } publicinttripleX() { return 3 * x; } privateintsubXhelper() { returnx - 1; } publicintsubX() { returnsubXhelper(); } } publicclass B extends A { privateintx; publicinty; public B(intxA, intxB) { super(xA); this.x = xB; this.y = xA + xB; } publicintgetX() { returnx; } publicintsuperX() { returnsuper.getX(); } publicinttenTimesX() { return 10*x; } privateintsubXhelper() { returnx-2; } } A a = new A (1); A b = new B (2, 22); Output / Notes System.out.println(a.y); System.out.println(b.y); System.out.println(((B)b).y); B bb= (B)b; System.out.println(bb.y); System.out.println(((A)bb).y); 2 4 24 24 4

  21. מחלקות אבסטרקטיות • כאשר רוצים לחלוק קוד משותף בין מספר מחלקות למרות שאין רצון לאפשר יצירת אובייקטים ממחלקת האב. • מכילה קוד משותף. • קובעת אילו שיטות אבסטרקטית על תתי המחלקות לממש. • תת-מחלקה קונקרטית מממשת שיטות אבסטרקטיות.

  22. מחלקות אבסטרקטיות public abstractclass<name> { public abstractvoid <method name> ( ... ); … } • במחלקה אבסטרקטית יכולות להיות שיטות רגילות, כמו בכל מחלקה. • בנוסף יכולות להיות לה שיטות אבסטרקטיות: שיטות שההגדרה שלהן קיימת אבל אין להן מימוש. • אנו מכריזים על מחלקה או על שיטה כאבסטרקטית בעזרת המילה השמורה abstract.

  23. מחלקות אבסטרקטיות • מחלקה אבסטרקטית -לא ניתן ליצור ממנה מופעים. publicabstractclass Game { public Game() { … } … } Game g = new Game(); // Compilation error! • מחלקה שמרחיבה מחלקה אבסטרקטית ולא מממשת את כל השיטות האבסטרקטיות, חייבת להיות אבסטרקטית בעצמה.

  24. Spy Robot • Spy Robot (רובוט מעקב) הינו רובוט הנשלט מרחוק ומאפשר צילום תמונות ושלחתם. • רובוט מעקב יכול לבצע את הפעולות הבאות: • לצלם תמונות ולשדר אותן • לזוז קדימה / אחרונה • להסתובב ימינה / שמאל

  25. Spy Robot • נסתכל על 2 רובוטי מעקב • שניהם יכולים לצלם תמונות ולשדר באותה דרך אך הם זזים בדרכים שונות.

  26. Spy Robot publicabstractclass SpyRobot { private String model; public SpyRobot(String model) { this.model=model; } public String getModel() { returnthis.model; } publicabstractvoid moveForward(); publicabstractvoid moveBackward(); publicabstractvoid turnLeft(); publicabstractvoid turnRight(); publicvoid takePicture() { ... } publicvoid chargeBattery() { ... } }

  27. Roboquad – Spy Robot publicclass LegsSpyRobot extends SpyRobot { public LegsSpyRobot() { super("Roboquad"); } publicvoid moveForward() { for(int i=0; i<4; i++) this.moveLeg(i, 1); } publicvoid moveBackward() { for(int i=0; i<4; i++) this.moveLeg(i, -1); } publicvoid turnLeft() { this.moveLeg(0,-1); this.moveLeg(1,-1); this.moveLeg(2,1); this.moveLeg(3,1); } // direction {1=forward, -1=backward} privatevoid moveLeg(int legId, int dir) { ... }; } 3 1 2 0 publicvoid turnRight() { this.moveLeg(0,1); this.moveLeg(1,1); this.moveLeg(2,-1); this.moveLeg(3,-1); }

  28. Spyke – Spy Robot publicclass WheelsSpyRobot extends SpyRobot { public WheelsSpyRobot() { super("Spyke"); } publicvoid moveForward() { this.turnWheels(1,1); } publicvoid moveBackward() { this.turnWheels(-1,-1); } publicvoid turnLeft() { this.turnWheels(0,-1); } publicvoid turnRight() { this.turnWheels(-1,0); } // direction {1=forward, 0=stop, -1=backward} privatevoid turnWheels(int rightDir,int leftDir) { ... }; // move features publicvoid waveHands() { ... } }

  29. Fly – Spy Robot את זה אתם כבר יכולים לממש לבד ?

  30. דוגמא נוספת • נממש משחקים מתורת המשחקים ע"י הורשה: • משחק מוגדר על ידי מערכת של פעולות אפשריות ושיטת ניקוד. • במשחק משחקים שני שחקנים כאשר שני השחקנים בוחרים פעולה בו-זמנית. • בהינתן שתי הבחירות של השחקנים יקבלו השחקנים ניקוד ע"פ בחירתם.

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

  32. דוגמה: דילמת האסיר • המשטרה עוצרת שני עבריינים שביצעו פשע משותף, ומפרידה ביניהם לצורך חקירה. • המשטרה מציעה לכל אחד מהם להעיד נגד רעהו, וכפרס מובטח לעד עונש מופחת. • בחירה מבין הפעולות האפשריות: להעיד או לשתוק. • ניקוד: • אם שניהם יעידו, ייכנס כל אחד מהם לכלא לחמש שנים. • אם רק אחד מהם יעיד ורעהו ישתוק, העד יצא מיד לחופשי וחברו ייכלא ל-15 שנה. • אם שניהם ישתקו, יכנס כל אחד מהם לשנה בכלא.

  33. המחלקות שעלינו לממש • פעולה Action • שם הפעולה ("אבן") • שחקן Player • שם השחקן (" Andrea Farina ") • מספר נקודות • בחירת פעולה(מהלך) מתוך קבוצת פעולות אפשריות. • משחק Game • קבוצת פעולות אפשריות • שיטת ניקוד • 2 שחקנים • שם המשחק

  34. מימוש המחלקה של פעולה כללית publicclass Action { private String name; public Action(String n) { this.name = n; } public String getName(){ returnthis.name; } publicboolean equals(Object other) { boolean ans = false; if(other instanceof Action) ans = this.name.equals(((Action)other).name); return ans; } }

  35. מימוש המחלקה של שחקן כללי publicabstractclass Player { private String name; privateintscore; public Player(String pname){ this.name= pname; this.score =0; } publicabstract Action selectAction(Action[] actions); publicboolean isWinner(Player p){ return (this.score > p.getScore()); } publicvoid updateScore(int score){ this.score = this.score + score; } publicint getScore(){ returnthis.score; } }

  36. מימוש שחקן אקראי publicclass RandomPlayer extends Player{ public RandomPlayer(String name) { super(name); } public Action selectAction(Action[] actions){ int randIdx = (int)(Math.random()*actions.length); return actions[randIdx]; } }

  37. מימוש שחקן עיקבי publicclass ConsecutivePlayer extends Player { privateintlastIdx; public ConsecutivePlayer(String name) { super(name); this.lastIdx = 0; } public Action selectAction(Action[] actions) { this.lastIdx = (this.lastIdx + 1) % actions.length; return actions[this.lastIdx]; } }

  38. מימוש משחק כללי publicabstractclass Game { private Player p1, p2; private String name; //game name protected Action[] actions; // the set of actions public Game(Player p1, Player p2, String name){ this.p1 = p1; this.p2 = p2; this.name = name; this.initActions(); } // There is no real list of actions in a general game protectedabstractvoid initActions(); …

  39. מימוש משחק כללי (המשך) publicabstractclass Game { … publicvoid play(intturnCount) { for (inti=0; i<turnCount; i=i+1) this.playSingleTurn(); } privatevoidplaySingleTurn() { /* the selection order is not important * as each player does not * know the choice of the other player */ Action a1 = this.p1.selectAction(actions); Action a2 = this.p2.selectAction(actions); this.rewardPlayers(a1, a2); } // There is no real scoring strategy in a general game protectedabstractvoidrewardPlayers(Action a1, Action a2); …

  40. מימוש משחק כללי (המשך) publicabstractclass Game { … public Player getWinner () { if (this.p1.isWinner(this.p2)) returnthis.p1; else returnthis.p2; } protected Player getFirstPlayer() { returnthis.p1; } protected Player getSecondPlayer() { returnthis.p2; } }

  41. מימוש המשחק אבן נייר ומספריים publicclass RockPaperScissors extends Game{ public RockPaperScissors(Player p1, Player p2) { super(p1, p2, "Rock Paper Scissors"); } protectedvoid initActions(){ this.actions = new Action[3]; this.actions[0] = new Action("rock"); this.actions[1] = new Action("paper"); this.actions[2] = new Action("scissors"); } ...

  42. protectedvoid rewardPlayers(Action a1, Action a2) { int p1score = 0; if (!(a1.getName().equals(a2.getName()))) { if ((a1.getName().equals("rock") && a2.getName().equals("scissors")) || (a1.getName().equals("paper") && a2.getName().equals("rock")) || (a1.getName().equals("scissors") && a2.getName().equals("paper"))) { p1score = 1; } else { p1score = -1; } } this.getFirstPlayer().updateScore(p1score); this.getSecondPlayer().updateScore(-p1score); } }

  43. מימוש המשחק דילמת האסיר publicclass PrisonerDilemmas extends Game{ public PrisonerDilemmas(Player p1, Player p2) { super(p1, p2, "Prisoner's Dilemma"); } protectedvoid initActions(){ this.actions = new Action[2]; this.actions[0] = new Action("silent"); this.actions[1] = new Action("blame"); } ...

  44. protectedvoid rewardPlayers(Action a1, Action a2) { if (a1.getName().equals("blame") && a2.getName().equals("blame")) { this.getFirstPlayer().updateScore(-5); this.getSecondPlayer().updateScore(-5); } if (a1.getName().equals("silent") && a2.getName().equals("blame")) { this.getFirstPlayer().updateScore(-15); this.getSecondPlayer().updateScore(0); } if (a1.getName().equals("blame") && a2.getName().equals("silent")) { this.getFirstPlayer().updateScore(0); this.getSecondPlayer().updateScore(-15); } if (a1.getName().equals("silent") && a2.getName().equals("silent")) { this.getFirstPlayer().updateScore(-1); this.getSecondPlayer().updateScore(-1); } } }

More Related