תוכנה 1 תרגול מספר 9: הורשה מחלקות אבסטרקטיות חריגים בית הספר למדעי המחשב אוניברסיטת תל אביב.

Slides:



Advertisements
Similar presentations
Object Oriented 33 MCSD DORON AMIR
Advertisements

ממיבחניםC שאלות ++.
תוכנה 1 סמסטר א ' תשע " ב תרגול מס ' 7 * מנשקים, דיאגרמות וביטים * לא בהכרח בסדר הזה.
מבוא למדעי המחשב לתעשייה וניהול
בתרגול הקודם הורשה: –ניתן להרחיב רק מחלקה אחת –כל מה שלא private – עובר בהורשה –המילה השמורה super –יצירת היררכיה –Object היא שורש ההיררכיה –דריסה אופרטור.
1 תוכנה 1 תרגול 14 – סיכום. 2 קצת על מנשקים מנשק יכול להרחיב יותר ממנשק אחד שירותים במנשק הם תמיד מופשטים וציבוריים public interface MyInterface { public.
תכנות מונחה עצמים Object Oriented Programming (OOP) אתגר מחזור ב'
הורשה ופולימורפיזם 1 עיגול ריבוע משושה צורה מוטיבציה מנשק גרפי טיפוסי מורכב מ -Widgets 2 Entry Label Button Check Button.
תרגול 5 רקורסיות. רקורסיה קריאה של פונקציה לעצמה –באופן ישיר או באופן עקיף היתרון : תכנות של דברים מסובכים נעשה ברור ונוח יותר, מכיוון שזו למעשה צורת.
מבוא לשפת C חידות ונקודות חשובות נכתב על-ידי יורי פקלני. © כל הזכויות שמורות לטכניון – מכון טכנולוגי לישראל.
אוניברסיטת בן גוריון - מבוא למדעי המחשב 1 תרגול מספר 10  ממשקים o כללים בסיסיים o מימוש מספר ממשקים o דוגמת ממשק כחוזה  הורשה o כללים בסיסיים o דריסה.
תרגול חזרה. מבנה האובייקט תאר את מבנה האובייקט כולל מבנה טבלאות הפונקציות הוירטואליות עבור התכנית הבאה struct A { int x; virtual void a() {}; }; struct.
Formal Specifications for Complex Systems (236368) Tutorial #6 appendix Statecharts vs. Raphsody 7 (theory vs. practice)
תכנות תרגול 6 שבוע : תרגיל שורש של מספר מחושב לפי הסדרה הבאה : root 0 = 1 root n = root n-1 + a / root n-1 2 כאשר האיבר ה n של הסדרה הוא קירוב.
אתחולים ובנאים יצירת מופע חדש של עצם כוללת : הקצאת זכרון, אתחול, הפעלת בנאים והשמה לשדות במסגרת ריצת הבנאי נקראים גם הבנאי / ים של מחלקת הבסיס תהליך זה.
מערכות הפעלה ( אביב 2009) חגית עטיה ©1 מערכת קבצים log-structured  ה log הוא העותק היחיד של הנתונים  כאשר משנים בלוק (data, header) פשוט כותבים את הבלוק.
1 נושאי התרגול : תכנות גנרי - Templates ירושה ופולימורפיזם.
עקרון ההכלה וההדחה.
תכנות מונחה עצמים Object Oriented Programming (OOP) אתגר מחזור ב' Templates תבניות.
הורשה - Inheritance הרצאה מספר 5.
1 Spring Semester 2007, Dept. of Computer Science, Technion Internet Networking recitation #3 Internet Control Message Protocol (ICMP)
Safari On-line books. מה זה ספארי ספארי זו ספריה וירטואלית בנושא מחשבים היא כוללת יותר מ כותרים כל הספרים הם בטקסט מלא ניתן לחפש ספר בנושא מסוים.
אביב תשס " ה JCT תיכון תוכנה ד " ר ר ' גלנט / י ' לויאןכל הזכויות שמורות 1 פרק 7 ISP דוגמא נוספת.
1 Abstract Classes האם קיים אובייקט בשם רהיט? האם קיים אובייקט בשם כלי תחבורה? האם קיים אובייקט בשם כלי כתיבה? האם קיים אובייקט בשם אדם? האם קיים אובייקט.
1 מבוא למדעי המחשב רקורסיה. 2 רקורסיה היא שיטה לפתרון בעיות המבוססת על העיקרון העומד ביסוד אינדוקציה מתמטית: אם ידועה הדרך לפתור בעיה עבור המקרים הבסיסיים.
אתחול עצמים. אתחולים ובנאים יצירת מופע חדש של עצם כוללת: הקצאת זכרון, אתחול, הפעלת בנאים והשמה לשדות במסגרת ריצת הבנאי נקראים גם הבנאי/ם של מחלקת הבסיס.
תוכנה 1 תבנית העיצוב Observer 1 שחר מעוז בית הספר למדעי המחשב אוניברסיטת תל אביב.
המשך תכנות מונחה עצמים 1. היום בתרגול  הורשה  שיטות מיוחדות  פולימורפיזם 2.
תוכנה 1 בשפת Java תרגול מספר 8: הורשה אסף זריצקי ומתי שמרת בית הספר למדעי המחשב אוניברסיטת תל אביב.
פיתוח מערכות מידע Class diagrams Aggregation, Composition and Generalization.
Methods public class Demonstrate { public static void main (String argv[]) { public static void main (String argv[]) { int script = 6, acting = 9, directing.
מבוא למדעי המחשב לתעשייה וניהול הרצאה 7. סברוטינות subroutines.
1 תרגול 11: Design Patterns ומחלקות פנימיות 1 תוכנה 1.
 Client, Supplier ומה שביניהם ( ADT!).  שאלה 1: יצירת ADT עבור מעגל במישור נניח שלקוח מעוניין בפעולות הבאות : הזזת מעגל וחישוב שטח מעגל. הספק יספק ללקוח.
מבוא למדעי המחשב הרצאה 18: פולימורפיזם ומחלקות אבסטרקטיות 1.
תכנות מכוון עצמים ושפת ++C וויסאם חלילי. TODAY TOPICS: 1. Function Overloading & Default Parameters 2. Arguments By Reference 3. Multiple #include’s 4.
מבוא למדעי המחשב לתעשייה וניהול הרצאה 6. מפעל השעווה – לולאות  עד עכשיו  טיפלנו בייצור נרות מסוג אחד, במחיר אחיד  למדנו להתמודד עם טיפול במקרים שונים.
1 תרגול 11: Design Patterns ומחלקות פנימיות אסף זריצקי ומתי שמרת 1 תוכנה 1.
1 נתבונן בפונקציה הבאה public static int min(int[] a,int n) { int min = a[0]; for (int i = 1; (i < n ) && (i < a.length) ; i++) if (min > a[i]) min = a[i];
1 Formal Specifications for Complex Systems (236368) Tutorial #1 Course site:
עקרונות תכנות מונחה עצמים תרגול 11: OOP in C++. Outline  Where do the objects live ?  Inheritance  Slicing  Overriding vs Shadowing.
שימוש בעצם ממחלקה אחרת כמאפיין במחלקה הנוכחית
האוניברסיטה העברית בירושלים
תרגול 7: מנשקים, פולימורפיזם ועוד
מספרים אקראיים ניתן לייצר מספרים אקראיים ע"י הפונקציה int rand(void);
Object Oriented Programming
תרגול מספר 9: הורשה מחלקות אבסטרקטיות חריגים
Object Oriented Programming
Operators Overloading
Formal Specifications for Complex Systems (236368) Tutorial #1
תרגול 7: מנשקים, פולימורפיזם ועוד
Object Oriented Programming
מחלקות classes.
תוכנה 1 תרגול 13 – סיכום.
תוכנה 1 בשפת Java שיעור מספר 7: "אמא יש רק אחת (*)" (הורשה I)
תוכנה 1 תרגול 13 – סיכום.
תכנות מכוון עצמים בשפת JAVA
ממשקים - interfaces איך לאפשר "הורשה מרובה".
תרגול מספר 9: הורשה מחלקות אבסטרקטיות חריגים
תרגול מס' 6 מחלקות, עצמים, וקצת חוזים
תוכנה 1 בשפת Java שיעור מספר 8: "ירושה נכונה" (הורשה II)
ניתוח מערכות מידע תכנות ב C#
תכנות מכוון עצמים ושפת JAVA
תכנות מכוון עצמים ושפת JAVA
מבוא לתכנות מונחה עצמים Object Oriented Programming
תרגול 10 המשך תכנות מונחה עצמים.
תוכנה 1 תרגול 13 – סיכום.
תוכנה 1 תרגול 13 – סיכום.
Engineering Programming A
פולימורפיזם מתקדם ממשקים בC# עריכה ועיצוב: קרן הרדי
Presentation transcript:

תוכנה 1 תרגול מספר 9: הורשה מחלקות אבסטרקטיות חריגים בית הספר למדעי המחשב אוניברסיטת תל אביב

ירושה ממחלקות קיימות ראינו בהרצאה שתי דרכים לשימוש חוזר בקוד של מחלקה קיימת: הכלה + האצלה ירושה המחלקה היורשת יכולה להוסיף פונקציונאליות שלא היתה קיימת במחלקת הבסיס, או לשנות פונקציונאליות שקיבלה בירושה 2 הכלה (aggregation)– במחלקה א' יש שדה מטיפוס מחלקה ב' האצלה (delegation)– קוראים מתוך מתודות במחלקה א' למתודות של מחלקה ב'

דריסת שירותים המחלקה היורשת בדרך כלל מייצגת תת-משפחה של מחלקת הבסיס המחלקה היורשת יכולה לדרוס שירותים שהתקבלו בירושה כדי להשתמש בשירות המקורי (למשל מהשירות הדורס) ניתן לפנות לשירות המקורי בתחביר: super.methodName(…) 3

שימוש בשירות המקורי מתוך השירות הדורס 4 class B { protected int a; protected int b; public String toString(){ return "a: " + this.a + " b: " + this.b; } { class C extends B{ private int c; public String toString(){ return super.toString() + " c: " + this.c; {

ניראות והורשה שדות ושירותים פרטיים (private) של מחלקת הבסיס אינם נגישים למחלקה היורשת כדי לאפשר גישה למחלקות יורשות יש להגדיר להם נראות protected שימוש בירושה יעשה בזהירות מרבית, בפרט הרשאות גישה למימוש נשתמש ב protected רק כאשר אנחנו מתכננים היררכיות ירושה שלמות ושולטים במחלקה היורשת 5

צד הלקוח בהרצאה ראינו את המנשק IPoint, והצגנו 3 מימושים שונים עבורו ראינו כי לקוחות התלויים במנשק IPoint בלבד, ואינם מכירים את המחלקות המממשות, יהיו אדישים לשינויים עתידים בקוד הספק שימוש במנשקים חוסך שכפול בקוד לקוח, בכך שאותו קטע קוד עובד בצורה נכונה עם מגוון ספקים (פולימורפיזם) 6 > IPoint > CartesianPoint > PolarPoint > SmartPoint > Rectangle

הממשק IPoint 7 public interface IPoint { /** returns the x coordinate of the current point*/ public double getX(); /** returns the y coordinate of the current point*/ public double getY(); /** returns the distance between the current point and (0,0) */ public double rho(); /** returns the angle between the current point and the abscissa */ public double theta(); /** move the current point by dx and dy */ public void translate(double dx, double dy); /** rotate the current point by angle degrees with respect to (0,0) */ public void rotate(double angle); … }

צד הספק לעומת זאת, מנגנון ההורשה חוסך שכפול קוד בצד הספק ע"י הורשה מקבלת מחלקה את קטע הקוד בירושה במקום לחזור עליו. שני הספקים חולקים אותו הקוד ננסה לזהות את שכפול הקוד בין 3 מימושי המנשק IPoint ולרכז קטעים משותפים אלה במחלקת בסיס משותפת ממנה ירשו שלושת המימושים. 8 > IPoint > AbstPoint > CartesianPoint > PolarPoint > SmartPoint ? ?

מחלקות מופשטות Abstract Classes מחלקה מופשטת מוגדרת ע"י המלה השמורה abstract לא ניתן ליצור מופע של מחלקה מופשטת (בדומה למנשק) יכולה לממש מנשק מבלי לממש את כל השירותים המוגדרים בו זהו מנגנון המועיל להימנע משכפול קוד במחלקות יורשות 9

מחלקות מופשטות - דוגמא public abstract class A { public void f() { System.out.println(“A.f!!”); } abstract public void g(); } A a = new A(); public class B extends A { public void g() { System.out.println(“B.g!!”); } } A a = new B(); 10 X

11 private double x; private double y; public CartesianPoint(double x, double y) { this.x = x; this.y = y; } public double getX() { return x;} public double getY() { return y;} public double rho() { return Math.sqrt(x*x + y*y); } public double theta() { return Math.atan2(y,x);} private double r; private double theta; public PolarPoint(double r, double theta) { this.r = r; this.theta = theta; } public double getX() { return r * Math.cos(theta); } public double getY() { return r * Math.sin(theta); } public double rho() { return r;} public double theta() { return theta;} CartesianPointPolarPoint קשה לראות דמיון בין מימושי המתודות במקרה זה. כל 4 המתודות בסיסיות ויש להן קשר הדוק לייצוג שנבחר לשדות

12 public void rotate(double angle) { double currentTheta = Math.atan2(y,x); double currentRho = getRho(); x = currentRho * Math.cos(currentTheta+angle); y = currentRho * Math.sin(currentTheta+angle); } public void translate(double dx, double dy) { x += dx; y += dy; } public void rotate(double angle) { theta += angle; } public void translate(double dx, double dy) { double newX = getX() + dx; double newY = getY() + dy; r = Math.sqrt(newX*newX + newY*newY); theta = Math.atan2(newY, newX); } גם כאן קשה לראות דמיון בין מימושי המתודות, למימושים קשר הדוק לייצוג שנבחר לשדות CartesianPointPolarPoint

13 public double distance(IPoint other) { return Math.sqrt((x-other.getX()) * (x-other.getX()) + (y-other.getY())*(y-other.getY())); } public double distance(IPoint other) { double deltaX = getX()-other.getX(); double deltaY = getY()-other.getY(); return Math.sqrt(deltaX * deltaX + deltaY * deltaY); } הקוד דומה אבל לא זהה, נראה מה ניתן לעשות... ננסה לשכתב את CartesianPoint ע"י הוספת משתני העזר deltaX ו- deltaY CartesianPointPolarPoint

14 public double distance(IPoint other) { double deltaX = x-other.getX(); double deltaY = y-other.getY(); return Math.sqrt(deltaX * deltaX + (deltaY * deltaY ); } נשאר הבדל אחד: נחליף את x להיות getX() – במאזן ביצועים לעומת כלליות נעדיף תמיד את הכלליות public double distance(IPoint other) { double deltaX = getX()-other.getX(); double deltaY = getY()-other.getY(); return Math.sqrt(deltaX * deltaX + deltaY * deltaY); } CartesianPointPolarPoint

15 public double distance(IPoint other) { double deltaX = getX()-other.getX(); double deltaY = getY()-other.getY(); return Math.sqrt(deltaX * deltaX + deltaY * deltaY ); } שתי המתודות זהות לחלוטין! עתה ניתן להעביר את המתודה למחלקה AbstPoint ולמחוק אותה מהמחלקות CartesianPoint ו- PolarPoint public double distance(IPoint other) { double deltaX = getX()-other.getX(); double deltaY = getY()-other.getY(); return Math.sqrt(deltaX * deltaX + deltaY * deltaY ); } CartesianPointPolarPoint

public String toString() { return "(x=" + getX() + ", y=" + getY() + ", r=" + r + ", theta=" + theta + ")"; } 16 public String toString(){ return "(x=" + x + ", y=" + y + ", r=" + rho() + ", theta=" + theta() + ")"; } תהליך דומה ניתן גם לבצע עבור toString CartesianPointPolarPoint

17 מימוש המחלקה האבסטרקטית public abstract class AbstractPoint implements IPoint{ public double distance(IPoint other) { double deltaX = getX()-other.getX(); double deltaY = getY()-other.getY(); return Math.sqrt(deltaX * deltaX + deltaY * deltaY ); } public String toString() { return "(x=" + getX() + ", y=" + getY() + ", r=" + rho() + ", theta=" + theta() + ")"; }

18 public class PolarPoint extends AbstractPoint{ private double r; private double theta; public PolarPoint(double r, double theta) { this.r = r; this.theta = theta; public double getX() { return r * Math.cos(theta); public void rotate(double angle) { theta += angle; } … } ירושה מהמחלקה האבסטרקטית

חריגים נממש שירות המחשב ממוצע הרמוני על אוסף של מספרים. 19 public static double harmonicMean(Collection numbers){ if (numbers.isEmpty()){ return 0; } double denumerator = 0; for (int i : numbers){ denumerator += 1.0/i; } return numbers.size()/denumerator; { שאלה: ממוצע הרמוני מוגדר רק על מספרים חיוביים. מה נעשה אם נקבל מספר אי-חיובי ברשימה?

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

חריגים 21 public static double harmonicMean(Collection numbers) throws Exception{ if (numbers.isEmpty()){ return 0; } double denumerator = 0; for (int i : numbers){ if (i <= 0){ throw new Exception("wrong value in list: " + i); } denumerator += 1.0/i; } return numbers.size()/denumerator; { עלינו לייצר אובייקט חדש מטיפוס Exception ולהשתמש במילה השמורה throw בשביל לזרוק את השגיאה מצהירים על שגיאה שנזרקת בשירות

חריגים נוסיף שירות נוסף – השירות מקבל מפה: משם קובץ לאוסף המספרים שהוא מכיל, ומדפיס ממוצע הרמוני עבור כל קובץ. 22 public static void printMeansByFiles(Map > numbers) { for (Map.Entry > mapEntry: numbers.entrySet()){ double hMeanForFile = harmonicMean(mapEntry.getValue()); System.out.println("for file: " + mapEntry.getKey() + " hMean is: " + hMeanForFile); } Exception בקוד הזה יש שגיאת קומפילציה בגלל שגיאה שלא הצהרנו עליה אך גם לא טיפלנו בה

חריגים אפשרות ראשונה: לא נטפל בחריג, ורק נצהיר עליו במקרה הזה, מי שיצטרך להתמודד עם הטיפול בחריג הוא השירות שיקרא ל printMeansByFiles. 23 public static void printMeansByFiles(Map > filesInfo) throws Exception{ for (Map.Entry > mapEntry: filesInfo.entrySet()){ double hMeanForFile = harmonicMean(mapEntry.getValue()); System.out.println("for file: " + mapEntry.getKey() + " hMean is: " + hMeanForFile); }

חריגים אפשרות שניה: נטפל בחריג! 24 public static void printMeansByFiles(Map > filesInfo) { for (Map.Entry > mapEntry: filesInfo.entrySet()){ try{ double hMeanForFile = harmonicMean(mapEntry.getValue()); System.out.println("for file: " + mapEntry.getKey() + " hMean is: " + hMeanForFile); } catch (Exception e){ System.out.println("cannot calculate hMean for file " + mapEntry.getKey()); }

חריגים איך זה עובד? תוכנית זו מייצרת את הפלט: 25 public static void main(String[] args){ Map > files = new LinkedHashMap<>(); files.put("file1", Arrays.asList(1, 2, 3)); files.put("file2", Arrays.asList(1,2,-4)); files.put("file3", Arrays.asList(15,17,30)); printMeansByFiles(files); }

חריגים ובכל זאת יש בעיה – אנחנו מטפלים בכל שגיאה אפשרית שיכולה להיזרק מתוך harmonicMean, ועל הדרך יכולים להתעלם משגיאות שמעידות על באג אפשרי. במימוש שלנו הנחנו הנחה סמויה לגבי המפה, למרות שאין לנו דרך לדעת כיצד היא נוצרה (נניח שאין חוזה לשירות). מה יקרה במקרה הבא? 26 public static void main(String[] args){ Map > files = new LinkedHashMap<>(); files.put("file1", null); files.put("file2", Arrays.asList(1,2,-4)); files.put("file3", Arrays.asList(15,17,30)); printMeansByFiles(files); }

חריגים 27 public static double getHMeanForFile(String fileName) throws Exception{ if (numbers.isEmpty()) … } public static void printMeansByFiles(Map > filesInfo) … catch (Exception e){ System.out.println("cannot calculate hMean for file " + mapEntry.getKey()); } … } NullPointerException

חריגים מה נרצה לעשות במידה והמפה שלי מכילה null? יכול להיות שנרצה להתייחס לזה כמו לרשימה ריקה (שזה למעשה הטיפול שקיים כרגע בקוד). יכול להיות שנרצה להדפיס הודעה למשתמש: המפה מכילה null, אולי קרתה שגיאה בטעינת הקובץ? יכול להיות שנרצה לזרוק את השגיאה ולהטיל את הטיפול על מי שמשתמש ב printMeansByFiles אם נרצה להתייחס למקרה של מפה המכילה null באופן שונה ממפה המכילה מספר לא חיובי, עלינו לדעת להבדיל בין החריגים. הצעה: נוסיף בלוק except עבור NullPointerException ומה אם יש עוד שגיאות שיכולות להיזרק? 28

יצירת טיפוס חריג חדש 29 class HMeanException extends Exception{ public HMeanException(String message) { super("Harmonic Mean calculation error! " + message); } { ירושה מ Exception קריאה לבנאי של מחלקת האב. אם רוצים להשתמש בבנאי של מחלקת האב, זו חייבת להיות השורה הראשונה של הבנאי.

שימוש בטיפוס החריג החדש 30 public static double harmonicMean(Collection numbers) throws HMeanException { if (numbers.isEmpty()){ return 0; } double denumerator = 0; for (int i : numbers){ if (i <= 0){ throw new HMeanException("wrong value in list: " + i); } denumerator += 1.0/i; } return numbers.size()/denumerator; {

שימוש בטיפוס החריג החדש 31 public static void printMeansByFiles(Map > filesInfo) … catch (HMeanException e){ System.out.println("cannot calculate hMean for file " + mapEntry.getKey()); } … } הבלוק הזה יטפל רק בשגיאה שזרקנו מתוך harmonicMean, חריגים אחרים יזרקו הלאה.

שימוש בשגיאות – פורמט הודעת השגיאה עבור תוכנית זו נקבל את הפלט: 32 public static void printMeansByFiles(Map > filesInfo) … catch (HMeanException e){ System.out.println("cannot calculate hMean for file " + mapEntry.getKey()); e.printStackTrace(); } { public static void main(String[] args){ Map > files = new LinkedHashMap<>(); files.put("file2", Arrays.asList(1,2,-4)); files.put("file3", Arrays.asList(15,17,30)); printMeansByFiles(files); }

שימוש בשגיאות הדפסת פורמט שגיאה מצומצם יותר: פלט התוכנית יהיה: 33 public static void printMeansByFiles(Map > filesInfo) … catch (HMeanException e){ System.out.println("cannot calculate hMean for file " + mapEntry.getKey()); System.out.println(e.getMessage()) } { class HMeanException extends Exception{ public HMeanException(String message) { super("Harmonic Mean calculation error! " + message); }