תרגול 11 המשך תכנות מונחה עצמים היום בתרגול • כללי הרשאות בהורשה • חריגות • מחלקות אבסטרקטיות 2 כללי הרשאות ( )visibility modifiersבהורשה • – publicשדות ושיטות המוגדרים כ public-ניתנים לגישה מתוך ומחוץ למחלקה. • – protectedשדות ושיטות המוגדרים כ protected-ניתנים לגישה מתוך המחלקה וממחלקות היורשות מהמחלקה ,אך אינם ניתן לגישה ממחלקות אחרות *. (* מחלקות הנמצאות ב packageאחר protected .מתנהג כמו publicבאותו .)package • – privateשדות ושיטות המוגדרים כ private-אינם ניתנים לגישה מחוץ למחלקה. ניסיון לגשת לשדה או שיטה כזו מחוץ למחלקה יגרור שגיאת קומפילציה. 3 ) בהורשהvisibility modifiers( כללי הרשאות 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 4 ) בהורשהvisibility modifiers( כללי הרשאות זו,שיטה לא יכולה להידרס ע"י שיטה מרמת שיתוף נמוכה יותר : כלומר.שגיאת קומפילציה private אוprotected עםpublic • לא ניתן לדרוס שיטה private עם שיטהprotected • לא ניתן לדרוס שיטה public class Book { public String getName() { … } } Book b = new Dictionary(); System.out.println(b.getName()); public class Dictionary extends Book { protected String getName() { … } Compilation Error } ? מה ההיגיון מאחורי שגיאה זו:שאלה 5 כללי הרשאות ( )visibility modifiersבהורשה • משתנים אינם עוברים דריסה בהורשה. • שיטות שאינן privateעוברות בהורשה. – שיטות פרטיות נועדו למימוש פנימי של מחלקת האב ,ואינן ניתנות לשימוש ע"י תת מחלקה. – תת-מחלקה לא מכירה את המשתנים והשיטות הפרטיות של מחלקת האב שלה, ולכן עשויה להכריז על משתנים ושיטות פרטיות בעלי אותו שם וחתימה. דוגמה: • חנות היא סוג של עסק – – עסק :דמי שכירות ,עובדים ,הוצאות חודשיות. חנות :פריטי סחורה ,הוצאות חודשיות הכוללות אחזקת מלאי. • כל אחת מהמחלקות מומשה ע"י מתכנת אחר • בכל אחת מימוש שונה לשיטה פרטית )(calcSum 6 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; } ... } 7 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; } ... } protected - לcalcSum אם נשנה את ההגדרה של:שאלה ?monthlyExpenses מה תחשב 8 סיכום חוקי גישה לשיטות ושדות בהורשה ב Java • טיפוס המשתנה (טיפוס המצביע )reference type /קובע בזמן הידור אילו שיטות ניתן להפעיל על המשתנה ולאילו שדות של המשתנה ניתן לגשת. • בקריאה לשיטה שאינה פרטית ,המופיעה הן במחלקת-אב והן בתת-מחלקה ,אם ע"י קריאה ישירה או ע"י שימוש באופרטור השייכות ( ,).הקוד המופעל נקבע בהתאם למחלקת האובייקט בפועל ) )instance typeשעליו מופעלת השיטה (ומשם בסריקה למעלה לפי היררכית ההורשה). • שיטה פרטית נגישה רק בתוך ה scope -של המחלקה בה היא מוגדרת .בקריאה לשיטה פרטית ,הקוד המופעל נקבע לפי ה - scopeבו ממוקמת הקריאה. 9 סיכום חוקי גישה לשיטות ושדות בהורשה ב Java • בגישה לשדה (קריאה או השמה) ,ע"י גישה ישירה (ללא אופרטור השייכות) ,הגישה לשדה נקבעת לפי הscope - בה ממוקמת הגישה (ומשם בסריקה למעלה לפי היררכית ההורשה). • בגישה לשדה (קריאה או השמה) שאינו פרטי ע"י אופרטור השייכות ,הגישה נקבעת בהתאם למחלקת טיפוס המשתנה ) )reference typeשעליו מופעלת השיטה (ומשם בסריקה למעלה לפי היררכית ההורשה). 10 דוגמה להורשה (שאלה ממבחן) 11 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(); } } 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; } } 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 !! 12 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 a = new A (1); A b = new B (2, 22); 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; } } Output / Notes B bb = (B)b; System.out.println(bb.superX()); 2 System.out.println(((B)b).superX()); System.out.println(a.tripleX()); System.out.println(b.tripleX()); 2 3 6 13 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(); } } 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; } } A a = new A (1); A b = new B (2, 22); Output / Notes System.out.println(((B)a).tenTimesX()); ClassCastException: A cannot be cast to B System.out.println(((B)b).tenTimesX()); System.out.println(b.doubleX()); 220 44 System.out.println(b.subX()); 1 14 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 a = new A (1); A b = new B (2, 22); 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); 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; } } Output / Notes 2 4 24 24 4 15 חריגות ()Exceptions • חריגה היא אירוע המתרחש במהלך תוכנית המפר את תהליך הריצה הנורמאלי של פקודות התוכנית. • לעיתים חריגות מתרחשות בגלל תקלות בלתי צפויות ,כגון בעיה בקובץ אליו כותבים (למשל אין הרשאות כתיבה), ולעיתים בגלל תקלות תוכנה, כגון שליחת פרמטר לא מתאים לפונקציה. 16 RuntimeExceptions כבר נתקלנו ב :ArithmeticException • ניסיון חלוקה באפס :IndexOutOfBoundsException • חריגה ממערך :NullPointerException • null ניסיון לפעול על משתנה שאינו פרימיטיבי בעל ערך .throw באמצעותRuntimeException וראינו כי ניתן לזרוק 17 Throw RuntimeException public class Car { private final int MAX_SPEED = 210; private final int MIN_SPEED = -20; private int speed; … public void setSpeed(int speed){ if ((speed >= MIN_SPEED) && (speed <= MAX_SPEED)) this.speed = speed; else throw new RuntimeException(“Illegal speed”); } } public static void 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) 18 Exceptions סוגי Object Exception IOException RuntimeException NullPointerException 19 חריגות • ניתן לייצר חריגה ע"י פקודת throwהמייצרת את אירוע החריגה. • ישנן שתי דרכים לטפל בחריגה: – לתפוס את ה Exception -על ידי בלוק tryוcatch- – להעביר את ה Exception -הלאה על ידי שימוש במילה השמורה throwsבכותרת הפונקציה שאנו כותבים. (טיפול בחריגות לא הכרחי עבור (RuntimeExceptions 20 Throw and Catch Exceptions public class Car { private final int MAX_SPEED = 210; private final int MIN_SPEED = -20; private int speed; … public void setSpeed(int speed) throws Exception { if ((speed >= MIN_SPEED) && (speed <= MAX_SPEED)) this.speed = speed; else throw new Exception(“Illegal speed”); } } public static void main(String[] args) { Car car = new Car(); car.setSpeed(100); } Compilation Error 21 Throw and Catch Exceptions public class Car { private final int MAX_SPEED = 210; private final int MIN_SPEED = -20; private int speed; … public void setSpeed(int speed) throws Exception { if ((speed >= MIN_SPEED) && (speed <= MAX_SPEED)) this.speed = speed; else throw new Exception(“Illegal speed”); } } public static void main(String[] args) { Car car = new Car(); try{ car.setSpeed(300); System.out.println(“This will not be printed!"); } 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 22 מחלקות אבסטרקטיות • כאשר רוצים לחלוק קוד משותף בין מספר מחלקות ,למרות שאין משמעות לאפשר יצירת אובייקטים ממחלקת האב. • מחלקה אבסטרקטית: – מכילה קוד משותף. – קובעת אילו שיטות אבסטרקטית על תת המחלקות לממש. – תת-מחלקה קונקרטית חייבת לממש את כל השיטות האבסטרקטיות. 23 מחלקות אבסטרקטיות { >public abstract class <name ;) public abstract void <method name> ( ... … } • במחלקה אבסטרקטית יכולות להיות שיטות רגילות ,כמו בכל מחלקה. • בנוסף יכולות להיות לה שיטות אבסטרקטיות :שיטות שההגדרה שלהן קיימת אבל אין להן מימוש. • מכריזים על מחלקה או על שיטה כאבסטרקטית באמצעות המילה השמורה .abstract 24 מחלקות אבסטרקטיות • מחלקה אבסטרקטית -לא ניתן ליצור ממנה מופעים. { public abstract class Game } … { )(public Game … } … !Game g = new Game(); // Compilation error • מחלקה שמרחיבה מחלקה אבסטרקטית ולא מממשת את כל השיטות האבסטרקטיות ,חייבת להיות אבסטרקטית בעצמה. 25 Spy Robot • ( Spy Robotרובוט מעקב) הינו רובוט הנשלט מרחוק ומאפשר צילום תמונות ושליחתן. • רובוט מעקב יכול לבצע את הפעולות הבאות: – לצלם תמונות ולשדר אותן – לזוז קדימה /אחורה – להסתובב ימינה /שמאלה 26 Spy Robot • נסתכל על 2רובוטי מעקב • לשניהם אותו רכיב צילום ותקשורת ,אבל הם נעים באופן שונה. 27 Spy Robot public abstract class SpyRobot { private String model; public SpyRobot(String model) { this.model = model; } public String getModel() { return this.model; } public public public public abstract abstract abstract abstract void void void void moveForward(); moveBackward(); turnLeft(); turnRight(); public void takePicture() { ... } public void chargeBattery() { ... } } 28 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() { for(int i=0; i<4; i++) this.moveLeg(i, -1); } 3 1 2 0 public void turnLeft() { this.moveLeg(0,-1); this.moveLeg(1,-1); this.moveLeg(2,1); this.moveLeg(3,1); } public void turnRight() { 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) { ... }; } 29 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() { ... } } 30 Fly – Spy Robot את זה אתם כבר יכולים לממש לבד... 31 מחלקות אבסטרקטיות Vs.ממשקים מחלקות אבסטרקטיות ממשקים לא ניתן ליצור מופעים לא ניתן ליצור מופעים שימוש ע"י ירושהextends , שימוש ע"י מימושוimplements , יכולה להכיל קוד של חלק מהשיטות הכרזה של שיטות ללא מימוש תת מחלקות יכולות לחלוק קוד (שיטות קונקרטיות במחלקה האבסטרקטית) ממשק הוא הכרזה על תכונה מופשטת, למממשים אין קוד משותף מחלקה יכולה לרשת מחלקה (אבסטרקטית) אחת בלבד מחלקה יכולה לממש מספר ממשקים אין הגבלה על שדות רק קבועים וסטאטיים (נחשב )Bad Style 32 מימוש משחק מתורת המשחקים • נממש מס' משחקים מתורת המשחקים ע"י הורשה: – משחק כללי מוגדר על ידי מערכת של פעולות אפשריות ושיטת ניקוד. – במשחק משחקים שני שחקנים כאשר שני השחקנים בוחרים פעולה בו-זמנית. – בהינתן שתי הבחירות של השחקנים יקבלו השחקנים ניקוד ע"פ בחירתם. 33 דוגמה :אבן נייר ומספריים • בחירה מבין שלוש הפעולות האפשריות (אבן ,נייר או מספריים): – אבן שוברת מספריים – מספריים גוזרים נייר – נייר עוטף אבן 34 דוגמה :דילמת האסיר • המשטרה עוצרת שני עבריינים שביצעו פשע משותף ,ומפרידה ביניהם לצורך חקירה. • המשטרה מציעה לכל אחד מהם להעיד נגד רעהו ,וכתמריץ מובטח לעד עונש מופחת. • בחירה מבין הפעולות האפשריות :להעיד או לשתוק. • ניקוד: – אם שניהם יעידו ,כל אחד יכלא לחמש שנים. – אם רק אחד יעיד ורעהו ישתוק ,העד ישוחרר וחברו ייכלא ל 15-שנה. – אם שניהם ישתקו ,כל אחד יכלא לשנה בלבד. 35 המחלקות שעלינו לממש • פעולה Action – שם הפעולה ("אבן") • שחקן Player – שם השחקן (" )" Andrea Farina – מספר נקודות – בחירת פעולה (מהלך) מתוך קבוצת פעולות אפשריות • משחק Game – קבוצת פעולות אפשריות – שיטת ניקוד – 2שחקנים – שם המשחק 36 מימוש המחלקה של פעולה כללית 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; } } 37 מימוש המחלקה של שחקן כללי 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; } } 38 מימוש שחקן אקראי 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]; } } 39 מימוש שחקן עקבי 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]; } } 40 מימוש משחק כללי public abstract class Game { private Player p1, p2; // participators 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 actual list of actions in a general game protected abstract void initActions(); … 41 )כללי (המשך מימוש משחק public abstract class Game { … public void play(int turnsCount) { for (int i=0; i<turnsCount; 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 actual scoring strategy in a general game protected abstract void rewardPlayers(Action a1, Action a2); … 42 )כללי (המשך מימוש משחק public abstract class Game { … public Player getWinner () { if (this.p1.isWinner(this.p2)) return this.p1; else return this.p2; } protected Player getFirstPlayer() { return this.p1; } protected Player getSecondPlayer() { return this.p2; } } 43 מימוש המשחק אבן נייר ומספריים 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"); } ... 44 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); } } 45 מימוש המשחק דילמת האסיר public class PrisonersDilemma extends Game{ public PrisonersDilemma(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(“sing"); } ... 46 protected void rewardPlayers(Action a1, Action a2) { if (a1.equals(a2)) { // Same actions if (a1.getName().equals(“sing") { // sing & sing 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(“sing") { // sing & silent this.getFirstPlayer().updateScore(0); this.getSecondPlayer().updateScore(-15); } else { // silent & sing this.getFirstPlayer().updateScore(-15); this.getSecondPlayer().updateScore(0); } } } } 47
© Copyright 2024 Paperzz