Presentation is loading. Please wait.

Presentation is loading. Please wait.

בתרגול הקודם הורשה: אופרטור instanceof המחלקה Object פולימורפיזם

Similar presentations


Presentation on theme: "בתרגול הקודם הורשה: אופרטור instanceof המחלקה Object פולימורפיזם"— Presentation transcript:

1 בתרגול הקודם הורשה: אופרטור instanceof המחלקה Object פולימורפיזם
ניתן להרחיב רק מחלקה אחת כל מה שלא private – עובר בהורשה המילה השמורה super יצירת היררכיה Object היא שורש ההיררכיה דריסה אופרטור instanceof המחלקה Object השיטות toString, equals פולימורפיזם חד כיווניות

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

3 היום בתרגול כללי הרשאות בהורשה מחלקות אבסטרקטיות

4 כללי הרשאות (visibility modifiers) בהורשה
public – שדות ושיטות המוגדרים כ-public ניתנים לגישה מתוך ומחוץ למחלקה. protected – שדות ושיטות המוגדרים כ-protected ניתנים לגישה מתוך המחלקה וממחלקות היורשות מהמחלקה, אך אינם ניתן לגישה ממחלקות אחרות *. (* ממחלקות אחרות הנמצאות ב package אחר. protected מתנהג כמו public באותו package) private – שדות ושיטות המוגדרים כ-private אינם ניתנים לגישה מחוץ למחלקה. ניסיון לגשת לשדה או שיטה כזו מחוץ למחלקה יעורר שגיאת קומפילציה. Access Levels Modifier Class Package Subclass World public Y Y Y Y protected Y Y Y N no modifier Y Y N N private Y N N N

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

6 כללי הרשאות (visibility modifiers) בהורשה
משתנים אינם עוברים דריסה בהורשה. שיטות שאינן private עוברות בהורשה. שיטות פרטיות נועדו למימוש פנימי של מחלקת האב, ואינן ניתנות לשימוש ע"י תת מחלקה. תת-המחלקה לא מכירה את המשתנים והשיטות הפרטיים של המחלקת האב, ממנה היא יורשת, ולכן עשויה גם להכריז על משתנים ושיטות פרטיים בעלי אותו שם וחתימה. Shadowed variables ca be accessed explicitly.

7 סיכום חוקי גישה לשיטות ושדות בהורשה ב-Java:
טיפוס המשתנה (טיפוס המצביע/ reference type) קובע בזמן הידור אילו שיטות ניתן להפעיל על המשתנה ולאילו שדות של המשתנה ניתן לגשת. בקריאה לשיטה שאינה פרטית המופיעה במחלקת-אב ובתת-מחלקה, אם ע"י קריאה ישירה או ע"י שימוש באופרטור השייכות (.), הקוד המופעל נקבע בהתאם למחלקת האובייקט בפועלinstance type) ) שעליו מופעלת השיטה (ומשם בסריקה מלמטה למעלה לפי היררכית ההורשה) - שיטת הבצל. שיטה פרטית נגישה רק בתוך ה-scope של המחלקה בה היא מוגדרת. בקריאה לשיטה פרטית, הקוד המופעל נקבע לפי ה-scope בו ממוקמת הקריאה. בגישה לשדה (קריאה או השמה), ע"י גישה ישירה (ללא אופרטור השייכות), הגישה לשדה נקבעת לפי ה-scope בו ממוקמת הגישה (ומשם בסריקה מלמטה למעלה לפי היררכית ההורשה). בגישה לשדה (קריאה או השמה) שאינו פרטי, ע"י אופרטור השייכות, הגישה נקבעת בהתאם למחלקת טיפוס המשתנהreference type) ) שעליה שייך השדה (ומשם בסריקה מלמטה למעלה לפי היררכית ההורשה). למה זה הגיוני? לשיטה פרטית לא ניתן לקרוא ממחלקה אחרת, לכן אם מנסים להפעיל שיטה פרטית, יש רק מקום אחד שבו אפשר לחפש אותה. שיטת הבצל – מתחילים מהשכבה העליונה ומקלפים שכבות (עולים בעץ ההורשה) 1. בודקים האם לטיפוס המשתנה קיימת השיטה המתאימה \ השדה המתאים. 2. אם מדובר בשיטה: 2.1 שיטה שאינה פרטית – לפי טיפוס האובייקט ושימוש בשיטת הבצל. 2.2 שיטה פרטית – לפי ה-scope בו ממוקמת הקריאה. 3. אם מדובר בשדה: 3.1 גישה ישירה (ללא אופרטור השייכות) – לפי ה-scope בו ממוקמת הגישה ושימוש בשיטת הבצל. 3.2 גישה ע"י אופרטור השייכות לשדה שאינו פרטי – לפי טיפוס המשתנה ושימוש בשיטת הבצל. שיטה שאינה פרטית – שיטת הבצל שיטה פרטית – לפי ה-scope גישה ישירה לשדה – לפי ה-scope גישה לשדה שאינו פרטי ע"י אופרטור השייכות (אופקטור הנקודה) – בהתאם לטיפוס המשתנה סיכום: יורשים רק מה שלא private. אם שיטה מוגדרת כפרטית, הגישה תהיה לשיטה ב-scope שבו היא נקראה. אם שיטה מוגדרת protected או public, פועלים לפי שיטת הבצל. בפנייה לשדה בתוך מחלקה, יש חיפוש החל מהרמה הנוכחית פנימה. שיטה לא private – תמיד לפי שיטת הבצל. בשדות לא פועלים לפי שיטת הבצל.

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

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

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

11 Business s = new Shop(); s.monthlyExpenses()
איך תרוץ התוכנית הבאה? שיטה פרטית נגישה רק בתוך ה-scope של המחלקה בה היא מוגדרת. בקריאה לשיטה פרטית, הקוד המופעל נקבע לפי ה-scope בו ממוקמת הקריאה. Business s = new Shop(); s.monthlyExpenses() Shop extends Business { public double monthlyExpenses() { double itemPrices = calcSum(); return itemPrices super.monthlyExpenses(); } private double calcSum() {…} Business { public double monthlyExpenses() { double salaries = calcSum(); return this.monthlyRent + salaries; } private double calcSum() {…}

12 Business s = new Shop(); s.monthlyExpenses()
שאלה: אם נשנה את המאפיין של calcSum ל-protected , מה תחשב monthlyExpenses? בקריאה לשיטה שאינה פרטית המופיעה במחלקת-אב ובתת-מחלקה, אם ע"י קריאה ישירה או ע"י שימוש באופרטור השייכות (.), הקוד המופעל נקבע בהתאם למחלקת האובייקט בפועלinstance type) ) שעליו מופעלת השיטה (ומשם בסריקה מלמטה למעלה לפי היררכית ההורשה) - שיטת הבצל. Business s = new Shop(); s.monthlyExpenses() Shop extends Business { public double monthlyExpenses() { double itemPrices = calcSum(); return itemPrices super.monthlyExpenses(); } protected double calcSum() {…} Business { public double monthlyExpenses() { double salaries = calcSum(); return this.monthlyRent + salaries; } protected double calcSum() {…}

13 שאלה: ומה במקרה הזה? בקריאה לשיטה שאינה פרטית המופיעה במחלקת-אב ובתת-מחלקה, אם ע"י קריאה ישירה או ע"י שימוש באופרטור השייכות (.), הקוד המופעל נקבע בהתאם למחלקת האובייקט בפועלinstance type) ) שעליו מופעלת השיטה (ומשם בסריקה מלמטה למעלה לפי היררכית ההורשה) - שיטת הבצל. Shop s = new Shop(); s.monthlyExpenses() אותו דבר...

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

15 public class A { private int x; public int y; public A(int x) { this.x = x; this.y = 2*x; } public int getX() { return x; } public int doubleX() { return 2 * getX(); } public int tripleX() { return 3 * x; } private int subXhelper() { return x - 1; } public int subX() { return subXhelper(); a X=1 Y=2 public class B extends A { private int x; public int y; public B(int xA, int xB) { super(xA); this.x = xB; this.y = xA + xB; } public int getX() { return x; } public int superX() { return super.getX(); public int tenTimesX() { return 10*x; } private int subXhelper() { return x-2; } b X=22 Y=24 X=2 Y=4 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 !! (The method superX() is undefined for the type A) if (b instanceof B) System.out.println(b.superX()); Compilation Error !!

16 public class A { private int x; public int y; public A(int x) { this.x = x; this.y = 2*x; } public int getX() { return x; } public int doubleX() { return 2 * getX(); } public int tripleX() { return 3 * x; } private int subXhelper() { return x - 1; } public int subX() { return subXhelper(); a X=1 Y=2 public class B extends A { private int x; public int y; public B(int xA, int xB) { super(xA); this.x = xB; this.y = xA + xB; } public int getX() { return x; } public int superX() { return super.getX(); public int tenTimesX() { return 10*x; } private int subXhelper() { return x-2; } b X=22 Y=24 X=2 Y=4 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

17 public class A { private int x; public int y; public A(int x) { this.x = x; this.y = 2*x; } public int getX() { return x; } public int doubleX() { return 2 * getX(); } public int tripleX() { return 3 * x; } private int subXhelper() { return x - 1; } public int subX() { return subXhelper(); a X=1 Y=2 public class B extends A { private int x; public int y; public B(int xA, int xB) { super(xA); this.x = xB; this.y = xA + xB; } public int getX() { return x; } public int superX() { return super.getX(); public int tenTimesX() { return 10*x; } private int subXhelper() { return x-2; } b X=22 Y=24 X=2 Y=4 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

18 public class A { private int x; public int y; public A(int x) { this.x = x; this.y = 2*x; } public int getX() { return x; } public int doubleX() { return 2 * getX(); } public int tripleX() { return 3 * x; } private int subXhelper() { return x - 1; } public int subX() { return subXhelper(); a X=1 Y=2 public class B extends A { private int x; public int y; public B(int xA, int xB) { super(xA); this.x = xB; this.y = xA + xB; } public int getX() { return x; } public int superX() { return super.getX(); public int tenTimesX() { return 10*x; } private int subXhelper() { return x-2; } b X=22 Y=24 X=2 Y=4 A a = new A (1); A b = new B (2, 22); Output / Notes בגישה לשדה (קריאה או השמה), ע"י גישה ישירה (ללא אופרטור השייכות), הגישה לשדה נקבעת לפי ה-scope בו ממוקמת הגישה (ומשם בסריקה מלמטה למעלה לפי היררכית ההורשה). 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

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

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

21 מחלקות אבסטרקטיות מחלקה אבסטרקטית - לא ניתן ליצור ממנה מופעים.
public abstract class Game { public Game() { … } } Game g = new Game(); // Compilation error! מחלקה שמרחיבה מחלקה אבסטרקטית ולא מממשת את כל השיטות האבסטרקטיות, חייבת להיות אבסטרקטית בעצמה. דוגמה לצורך במחלקה אבסטרקטית: נניח שאנחנו רוצים לממש מחלקה שמגדירה מצולע (פוליגון) במישור. נניח שכל המצולעים נתונים כמערך של נקודות. לכל המצולעים יש שטח ויש היקף. נשים לך ששיטת חישוב ההיקף היא זהה עבור כל המצולעים, קרי, עבור כל זוג נקודות עוקבות במערך, חשב את המרחק ביניהן וסכום את כל המרחקים. לכן אותה שיטה (אותו מימוש) יכולה לשמש את כל המצולעים. נשים לב ששיטת חישוב השטח שונה בין מצולע למצולע – עבור מרובעים גובה * רוחב, עבור משולשים צלע כפול גובה וכו' – לכן יש צורך במימושים שונים במחלקות שונות. אי לכך, כאשר נגדיר את המחלקה פוליגון, תהיינה בה לפחות שתי שיטות: אחת אבסטרקטית (חישוב שטח) ואחת רגילה וממומשת (חישוב היקף). מכיוון שקיימת שיטה אבסטרקטית, גם המחלקה פוליגון תהיה אבסטרקטית.

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

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

24 Spy Robot public abstract class SpyRobot { private String model;
public SpyRobot(String model) { this.model=model; } public String getModel() { return this.model; public abstract void moveForward(); public abstract void moveBackward(); public abstract void turnLeft(); public abstract void turnRight(); public void takePicture() { ... } public void chargeBattery() { ... }

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

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

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

28 מחלקה אבסטרקטית ממשק לא ניתן ליצור מופעים שימוש ע"י ירושה (extends)
שימוש ע"י מימושו (implements) יכולה להכיל קוד של חלק מהשיטות הכרזה של שיטות בלי מימוש יורשי מחלקה זו יהיו בעלי קוד משותף וכן בעלי התנהגויות שונות (השיטות האבסטרקטיות) ממשק הוא הכרזה על תכונה מופשטת, למממשים אין קוד משותף. מחלקה יכולה לרשת מחלקה (אבסטרקטית) אחת בלבד מחלקה יכולה לממש מספר ממשקים אין הגבלה על שדות אין שיטות פרטיות רק קבועים סטאטיים (implicitly)

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

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

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

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

33 מימוש המחלקה של שחקן כללי
public abstract class Player { private String name; private int score; public Player(String name){ this.name = name; this.score = 0; } public abstract Action selectAction(Action[] actions); public boolean isWinner(Player p){ return (this.score > p.getScore()); public void updateScore(int score){ this.score = this.score + score; public int getScore(){ return this.score;

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

35 מימוש שחקן עיקבי public class ConsecutivePlayer extends Player { private int lastIdx; 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];

36 מימוש משחק כללי public abstract class 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 protected abstract void initActions();

37 מימוש משחק כללי (המשך) public abstract class Game { … public void play(int turnCount) { for (int i=0; i<turnCount; i=i+1) this.playSingleTurn(); } private void playSingleTurn() { /* 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 protected abstract void rewardPlayers(Action a1, Action a2);

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

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

40 protected void rewardPlayers(Action a1, Action a2) {
int p1score = 0; if (!(a1.equals(a2))) {// Different actions 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);

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

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

43 protected void rewardPlayers(Action a1, Action a2) { if (a1
protected void rewardPlayers(Action a1, Action a2) { if (a1.equals(a2)) { // Same actions if (a1.getName().equals("blame") { // blame & blame this.getFirstPlayer().updateScore(-5); this.getSecondPlayer().updateScore(-5); } else { // silent & silent this.getFirstPlayer().updateScore(-1); this.getSecondPlayer().updateScore(-1); } } else { // Different actions if (a1.getName().equals("blame") { // blame & silent this.getFirstPlayer().updateScore(0); this.getSecondPlayer().updateScore(-15); } else { // silent & blame this.getFirstPlayer().updateScore(-15); this.getSecondPlayer().updateScore(0);


Download ppt "בתרגול הקודם הורשה: אופרטור instanceof המחלקה Object פולימורפיזם"

Similar presentations


Ads by Google