בתרגול הקודם
• הורשה:
–
–
–
–
–
–
ניתן להרחיב רק מחלקה אחת
כל מה שלא – privateעובר בהורשה
המילה השמורה super
יצירת היררכיה
Objectהיא שורש ההיררכיה
דריסה
• אופרטור instanceof
• המחלקה Object
– השיטות equals ,toString
• פולימורפיזם
1
– חד כיווניות
תרגול 11
המשך תכנות מונחה עצמים
2
היום בתרגול
• כללי הרשאות בהורשה
• מחלקות אבסטרקטיות
3
כללי הרשאות ( )visibility modifiersבהורשה
– publicשדות ושיטות המוגדרים כ public-ניתנים לגישה מתוך
ומחוץ למחלקה.
– protectedשדות ושיטות המוגדרים כ protected-ניתנים לגישה
מתוך המחלקה וממחלקות היורשות מהמחלקה ,אך אינם ניתן לגישה
ממחלקות אחרות *.
(* ממחלקות אחרות הנמצאות ב packageאחר protected .מתנהג כמו publicבאותו
)package
– privateשדות ושיטות המוגדרים כ private-אינם ניתנים לגישה
מחוץ למחלקה .ניסיון לגשת לשדה או שיטה כזו מחוץ למחלקה יעורר
שגיאת קומפילציה.
4
) בהורשהvisibility modifiers( כללי הרשאות
זו שגיאת,שיטות לא יכולות להידרס ע"י שיטה מרמת שיתוף נמוכה יותר
: כלומר.קומפילציה
private אוprotected עםpublic – לא ניתן לדרוס שיטה
private עם שיטהprotected – לא ניתן לדרוס שיטה
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() );
? מה ההיגיון מאחורי שגיאה זו:שאלה
בלעדיה הייתה מתקבלת סתירה לעקרון
הפולימורפיזם
5
כללי הרשאות ( )visibility modifiersבהורשה
•
•
6
משתנים אינם עוברים דריסה בהורשה.
שיטות שאינן privateעוברות בהורשה.
– שיטות פרטיות נועדו למימוש פנימי של מחלקת האב ,ואינן ניתנות לשימוש ע"י
תת מחלקה.
– תת-המחלקה לא מכירה את המשתנים והשיטות הפרטיים של המחלקת האב,
ממנה היא יורשת ,ולכן עשויה גם להכריז על משתנים ושיטות פרטיים בעלי
אותו שם וחתימה.
סיכום חוקי גישה לשיטות ושדות בהורשה ב:Java-
.1טיפוס המשתנה (טיפוס המצביע )reference type /קובע בזמן הידור אילו שיטות
ניתן להפעיל על המשתנה ולאילו שדות של המשתנה ניתן לגשת.
.2
.3
.4
.5
7
בקריאה לשיטה שאינה פרטית המופיעה במחלקת-אב ובתת-מחלקה ,אם ע"י
קריאה ישירה או ע"י שימוש באופרטור השייכות ( ,).הקוד המופעל נקבע בהתאם
למחלקת האובייקט בפועל ) )instance typeשעליו מופעלת השיטה (ומשם
בסריקה מלמטה למעלה לפי היררכית ההורשה) -שיטת הבצל.
שיטה פרטית נגישה רק בתוך ה scope-של המחלקה בה היא מוגדרת .בקריאה
לשיטה פרטית ,הקוד המופעל נקבע לפי ה scope-בו ממוקמת הקריאה.
למה זה הגיוני?
אופרטורלהפעיל
אם מנסים
גישהאחרת,
ממחלקה
או לקרוא
ניתן
פרטית לא
השייכות),
לכןללא
ישירה (
השמה) ,ע"י
קריאה
לשיטהלשדה (
בגישה
אותה.
לחפש
שבובואפשר
מקום -אחד
פרטית ,יש
שיטה
ומשם בסריקה
הגישה (
ממוקמת
scope
רקלפי ה
נקבעת
הגישה לשדה
מלמטה למעלה לפי היררכית ההורשה).
בגישה לשדה (קריאה או השמה) שאינו פרטי ,ע"י אופרטור השייכות ,הגישה
נקבעת בהתאם למחלקת טיפוס המשתנה ) )reference typeשעליה שייך
השדה (ומשם בסריקה מלמטה למעלה לפי היררכית ההורשה).
דוגמא
•
דוגמה:
חנות היא סוג של עסק
–
•
•
–
–
8
עסק :דמי שכירות ,עובדים ,הוצאות חודשיות
חנות :פריטי סחורה ,הוצאות חודשיות הכוללות אחזקת מלאי.
כל מחלקה מומשה ע"י מתכנתת אחרת
בכל מחלקה מימוש שונה לשיטה פרטית calcSum() -
מבוא למדמ"ח ,אונ' בן-גוריון ,תש"ע
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;
}
......
}
9
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;
}
......
}
10
?איך תרוץ התוכנית הבאה
, בקריאה לשיטה פרטית. של המחלקה בה היא מוגדרת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() {…}
}
?monthlyExpenses מה תחשב,protected - לcalcSum אם נשנה את המאפיין של:שאלה
אם ע"י קריאה ישירה או ע"י,מחלקה-אב ובתת-בקריאה לשיטה שאינה פרטית המופיעה במחלקת
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() {…}
}
שאלה :ומה במקרה הזה?
בקריאה לשיטה שאינה פרטית המופיעה במחלקת-אב ובתת-מחלקה ,אם ע"י קריאה ישירה או ע"י
שימוש באופרטור השייכות ( ,).הקוד המופעל נקבע בהתאם למחלקת האובייקט בפועל instance
) )typeשעליו מופעלת השיטה (ומשם בסריקה מלמטה למעלה לפי היררכית ההורשה) -שיטת
הבצל.
;)(Shop s = new Shop
)(s.monthlyExpenses
אותו דבר...
דוגמה להורשה
(שאלה ממבחן)
14
a
public class A {
public class B extends A {
b
private int x;
private int x;
X=1
public int y;
public int y;
X=22
Y=2
public A(int x) {
public B(int xA, int xB) {
Y=24
this.x = x;
super(xA);
this.y = 2*x;
this.x = xB;
X=2
}
this.y = xA + xB;
Y=4
public int getX() { return x; }
}
public int doubleX() { return 2 * getX(); }
public int getX() { return x; }
public int tripleX() { return 3 * x; }
public int superX() {
private int subXhelper() { return x - 1; }
return super.getX();
public int subX() {
}
return subXhelper();
public int tenTimesX() { return 10*x; }
}
private int subXhelper() { return x-2; }
}
}
A a = new A (1);
A b = new B (2, 22);
System.out.println(a.getX());
System.out.println(b.getX());
System.out.println(b.superX());
Output / Notes
1
22
Compilation Error !! (The method superX()
is undefined for the type A)
if (b instanceof B)
System.out.println(b.superX()); Compilation Error !!
15
a
public class A {
public class B extends A {
b
private int x;
private int x;
X=1
public int y;
public int y;
X=22
Y=2
public A(int x) {
public B(int xA, int xB) {
Y=24
this.x = x;
super(xA);
this.y = 2*x;
this.x = xB;
X=2
}
this.y = xA + xB;
Y=4
public int getX() { return x; }
}
public int doubleX() { return 2 * getX(); }
public int getX() { return x; }
public int tripleX() { return 3 * x; }
public int superX() {
private int subXhelper() { return x - 1; }
return super.getX();
public int subX() {
}
return subXhelper();
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
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
16
a
public class A {
public class B extends A {
b
private int x;
private int x;
X=1
public int y;
public int y;
X=22
Y=2
public A(int x) {
public B(int xA, int xB) {
Y=24
this.x = x;
super(xA);
this.y = 2*x;
this.x = xB;
X=2
}
this.y = xA + xB;
Y=4
public int getX() { return x; }
}
public int doubleX() { return 2 * getX(); }
public int getX() { return x; }
public int tripleX() { return 3 * x; }
public int superX() {
private int subXhelper() { return x - 1; }
return super.getX();
public int subX() {
}
return subXhelper();
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()); Run-time Error:
ClassCastException: A cannot be cast to B
System.out.println(((B)b).tenTimesX()); 220
System.out.println(b.doubleX());
44
17
System.out.println(b.subX());
1
a
public class A {
public class B extends A {
b
private int x;
private int x;
X=1
public int y;
public int y;
X=22
Y=2
public A(int x) {
public B(int xA, int xB) {
Y=24
this.x = x;
super(xA);
this.y = 2*x;
this.x = xB;
X=2
}
this.y = xA + xB;
Y=4
public int getX() { return x; }
}
public int doubleX() { return 2 * getX(); }
public int getX() { return x; }
public int tripleX() { return 3 * x; }
public int superX() {
private int subXhelper() { return x - 1; }
return super.getX();
public int subX() {
}
return subXhelper();
public int tenTimesX() { return 10*x; }
}
private int subXhelper() { return x-2; }
}
}
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);
Output / Notes
ע"י גישה,)בגישה לשדה (קריאה או השמה
2
4 הגישה לשדה,)ישירה (ללא אופרטור השייכות
בו ממוקמת הגישהscope -נקבעת לפי ה
24
(ומשם בסריקה מלמטה למעלה לפי היררכית
.)ההורשה
24
18
4
מחלקות אבסטרקטיות
• כאשר רוצים לחלוק קוד משותף בין מספר מחלקות למרות שאין
רצון לאפשר יצירת אובייקטים ממחלקת האב.
• מחלקת האב:
– מכילה קוד משותף.
– קובעת אילו שיטות אבסטרקטית על תתי המחלקות לממש.
• תת-מחלקה קונקרטית מממשת שיטות אבסטרקטיות.
19
מחלקות אבסטרקטיות
{ >public abstract class <name
;) public abstract void <method name> ( ...
…
}
• במחלקה אבסטרקטית יכולות להיות שיטות רגילות ,כמו בכל
מחלקה.
• בנוסף יכולות להיות לה שיטות אבסטרקטיות :שיטות שההגדרה
שלהן קיימת אבל אין להן מימוש.
• אנו מכריזים על מחלקה או על שיטה כאבסטרקטית בעזרת המילה
השמורה .abstract
20
מחלקות אבסטרקטיות
• מחלקה אבסטרקטית -לא ניתן ליצור ממנה מופעים.
{ public abstract class Game
} … { )(public Game
…
}
!// Compilation error
;)(Game g = new Game
• מחלקה שמרחיבה מחלקה אבסטרקטית ולא מממשת את כל
השיטות האבסטרקטיות ,חייבת להיות אבסטרקטית בעצמה.
21
Spy Robot
• ( Spy Robotרובוט מעקב) הינו רובוט הנשלט מרחוק
ומאפשר צילום תמונות ושליחתן.
• רובוט מעקב יכול לבצע את הפעולות הבאות:
– לצלם תמונות ולשדר אותן
– לזוז קדימה /אחורה
– להסתובב ימינה /שמאלה
22
Spy Robot
• נסתכל על 2רובוטי מעקב
• שניהם יכולים לצלם תמונות ולשדר באותה דרך אך הם
זזים בדרכים שונות.
23
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() { ... }
}
24
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
2
public void turnRight() {
public void turnLeft() {
this.moveLeg(0,1);
this.moveLeg(0,-1);
this.moveLeg(1,1);
this.moveLeg(1,-1);
this.moveLeg(2,-1);
this.moveLeg(2,1);
this.moveLeg(3,-1);
this.moveLeg(3,1);
}
}
// direction {1=forward, -1=backward}
private void moveLeg(int legId, int dir) { ... };
}
1
0
25
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() { ... }
}
26
Fly – Spy Robot
האם את זה אתם כבר יכולים לממש לבד ?
27
מחלקה אבסטרקטית
ממשק
לא ניתן ליצור מופעים
לא ניתן ליצור מופעים
שימוש ע"י ירושה ()extends
שימוש ע"י מימושו ()implements
יכולה להכיל קוד של חלק מהשיטות
הכרזה של שיטות בלי מימוש
יורשי מחלקה זו יהיו בעלי קוד משותף וכן בעלי
התנהגויות שונות (השיטות האבסטרקטיות)
ממשק הוא הכרזה על תכונה מופשטת,
למממשים אין קוד משותף.
מחלקה יכולה לרשת מחלקה (אבסטרקטית)
אחת בלבד
מחלקה יכולה לממש מספר ממשקים
אין הגבלה על שדות
רק קבועים סטאטיים ()implicitly
אין שיטות פרטיות
אין שיטות פרטיות
28
דוגמא נוספת
• נממש משחקים מתורת המשחקים ע"י הורשה:
– משחק מוגדר על ידי מערכת של פעולות אפשריות
ושיטת ניקוד.
– במשחק משחקים שני שחקנים כאשר שני השחקנים
בוחרים פעולה בו-זמנית.
– בהינתן שתי הבחירות של השחקנים יקבלו השחקנים
ניקוד ע"פ בחירתם.
29
דוגמה :אבן נייר ומספריים
• בחירה מבין שלוש הפעולות האפשריות (אבן ,נייר
או מספריים).
– אבן שוברת מספריים.
– מספריים גוזרים נייר.
– נייר עוטף אבן.
30
http://www.youtube.com/watch?v=_PUEoDYpUyQ
המחלקות שעלינו לממש
• פעולה Action
– שם הפעולה ("אבן")
• שחקן Player
– שם השחקן (" )" Andrea Farina
– מספר נקודות
– בחירת פעולה (מהלך) מתוך קבוצת פעולות אפשריות.
• משחק Game
– קבוצת פעולות אפשריות
– שיטת ניקוד
– 2שחקנים
– שם המשחק
31
מימוש המחלקה של פעולה כללית
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;
}
}
32
מימוש המחלקה של שחקן כללי
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;
}
}
33
מימוש שחקן אקראי
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];
}
}
34
מימוש שחקן עיקבי
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];
}
}
35
מימוש משחק כללי
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();
…
36
)כללי (המשך
מימוש משחק
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);
…
37
)כללי (המשך
מימוש משחק
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;
}
}
38
מימוש המשחק אבן נייר ומספריים
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");
}
...
39
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);
}
}
40
דוגמה :דילמת האסיר
•
•
•
•
המשטרה עוצרת שני עבריינים שביצעו פשע משותף ,ומפרידה ביניהם
לצורך חקירה.
המשטרה מציעה לכל אחד מהם להעיד נגד רעהו ,וכפרס מובטח לעד
עונש מופחת.
בחירה מבין הפעולות האפשריות :להעיד או לשתוק.
ניקוד:
– אם שניהם יעידו ,ייכנס כל אחד מהם לכלא לחמש שנים.
– אם רק אחד מהם יעיד ורעהו ישתוק ,העד יצא מיד לחופשי וחברו ייכלא ל 15-שנה.
– אם שניהם ישתקו ,יכנס כל אחד מהם לשנה בכלא.
41
מימוש המשחק דילמת האסיר
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");
}
...
42
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);
}
}
}
}
43
© Copyright 2025 Paperzz