Survey
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
Interface
ממשקים
1
• ראינו כי ניתן לשמור אובייקטים במערכים באותו
אופן כמו משתנים רגילים.
• ננסה כעת לראות כיצד למיין מערך של אובייקטים
מסוג מסוים.
• נשתמש בשתי מחלקות חדשות Student ,ו – Car
2
Student
public class Student {
// Sate:
private String name;
private int id;
// Constructors:
public Student(int id, String name) {
this.name = name;
this.id = id;
}
// Behavior:
…
} // class Student
3
Car
public class Car {
// Sate:
private String company;
private int model;
// Constructors:
public Car(int model, String company) {
this.company = company;
this.model = model;
}
// Behavior:
…
} // class Car
4
נתבונן במערך של מצביעים לאוביקטים מטיפוס
:Students
;]Students[] arr = new Student[10
על מנת למיין אותו נבחר אחד מאלגוריתמי המיון
שלמדנו ,למשל InsertionSort
5
insertionSort
public static void insertionSort(int[]
array){
for (int i=1; i<array.length; i=i+1){
int value = array[i];
int j = i;
while(j>0 && (array[j-1] > value) ){
array[j] = array[j-1];
j = j-1;
}
array[j] = value;
}//for
}//insertionSort
6
מעבר למיון סטודנטים
• מהו הקושי העיקרי בשינוי הפונקציה כדי שתתאים
למיון סטודנטים?
פעולת ההשוואה כמובןarray[j-1] > value :
הפעולה הראשונה שצריך לעשות היא להחליט על
פעולת ההשוואה .למשל ,השוואת מספר תעודת
הזהות.
עכשיו ניתן לכתוב:
7
מיון סטודנטים
public static void insertionSort(Student[]
array){
for (int i=1; i<array.length; i = i+1){
Student value = array[i];
int j = i;
while(j>0 && (array[j-1].getId() >
value.getId())){
array[j] = array[j-1];
j = j-1;
}
array[j] = value;
}
}//insertionSort(Student[] array)
8
:• עכשיו ניתן להפעיל
Students[] arr=new Student[10];
insertionSort(arr);
?Car ומה עם
Car[] arr=new Car[10];
insertionSort(arr);//????
9
מיון מכוניות
public static void insertionSort(Car[]
array){
for (int i=1; i<array.length; i = i+1){
Car value = array[i];
int j = i;
while(j>0 && (array[j-1].getModel() >
value.getModel()) ){
array[j] = array[j-1];
j = j-1;
}
array[j] = value;
}
}//insertionSort(Car[] array)
10
...Object אז מה פתרון אפשרי? כמובן
public static void insertionSort(Object[]
array){
for (int i=1; i<array.length; i=i+1){
Object value = array[i];
int j = i;
while(j>0 && (array[j].???? > value.
????) ){
array[j] = array[j-1];
j = j-1;
}
array[j] = value;
}
}//insertionSort
11
ממשק Interface -
• אז כיצד נפתור זאת? היינו רוצים להגיד שכל
אובייקט שרוצה להיות בר-מיון יוכל להשתמש
בפונקציית המיון הזאת .ראינו רעיון דומה עם
equalsב ...ObjectSet
• אם היתה לנו דרך להוסיף תכונת "בר-השוואה"
לכל אובייקט שאנו רוצים למיין ,היינו בדרך
הנכונה.
• בדיוק למטרה זו ,ב JAVAקיים המושג ממשק
()interface
12
ממשק הוא הגדרת התנהגות
ללא מימוש
13
Comparable הממשק
public interface Comparable {
/**
* @param other an object to compare with this
* Comparable object
* @return a negative value, 0, or a positive value,
* if this object has a lower, an identical, or a
* higher rank in the order, respectively.
*/
public int compareTo(Object other);
}
14
הממשק Comparable
• בדוגמה שלנו ,הגדרנו את התכונה תכונה "בר-
השוואה":
;)public int compareTo(Object other
• שימו לב כי השיטה compareToהיא חסרת מימוש.
• השיטה compareToתחזיר מספר שלילי אם מקומו
של האובייקט היוזם את הקריאה בסידור קודם למקום
האובייקט המתקבל כפרמטר ,מספר חיובי אם מקומו
מאוחר ,ואפס אם מקומם זהה.
15
• ממשק הוא חוזה ,וככל חוזה ,יש לו שני צדדים:
– כל מחלקה יכולה להתחייב לממש את החוזה ,ובמקרה
כזה היא מחוייבת לממש את כל השיטות המפורטות
בחוזה.
– ניתן להתייחס באופן אחיד למופעים של מחלקות
המממשות חוזה מסוים מבלי לדעת מהן המחלקות
הקונקרטיות שלהם .התייחסות כזו מאפשרת להפעיל
על מופעים אלו את כל השיטות המופיעות בחוזה.
16
השוואה" חייב לממש את כל-מי שרוצה להיות בעל התכונה "בר
: לא יעבור קומפילציה, אחרת.השיטות המופיעות בממשק
public class Student implements Comparable{
…
public int compareTo(Object other) {
int otherId = ((Student)other).getId();
return id - otherId;
}
} // class Student
17
פתרון "מקצועי" יותר
public class Student implements Comparable{
…
public int compareTo(Object other) {
if (!(other instanceof Student)){
throw new RuntimeException(
"CompareTo got a non-Student
parameter.");
}
int otherId = ((Student)other).getId();
return id - otherId;
}
} // class Student
18
במקרה זה.אפשרות שנייה – סידור לקסיקוגרפי לפי שם
:String שלcompareTo ניתן להשתמש בשיטה
public class Student implements Comparable{
…
public int compareTo(Object other) {
if (!(other instanceof Student)){
throw new RuntimeException(
"CompareTo got a non-Student
parameter.");
}
String otherName =
((Student)other).getName();
return name.compareTo(otherName);
}
}
19 // class Student
:Car ועבור המחלקה
public class Car implements Comparable{
…
public int compareTo(Object other){
if (!(other instanceof Car)){
throw new RuntimeException("CompareTo
got a non-Car parameter.");
}
int otherModel = ((Car)other).getModel();
return model - otherModel;
}
} // class Car
20
בני השוואה
• עכשיו העצמים במחלקה Carוגם העצמים במחלקה Studentהם
בני-השוואה (כלומר – שתי המחלקות "חתמו על החוזה"
.)Comparable
• ב JAVAניתן להגדיר מצביעים אשר הטיפוס שלהם הוא ממשק,
ובכך להתייחס לאובייקט המוצבע לפי התכונות המחייבות אותו
אשר מופיעות בממשק .רעיון זה אינו מופרך – גם אנחנו מתייחסים
לפעמים לתכונות ספציפיות של סטודנט או מרצה ,ולפעמים
לתכונות משותפות של שניהם כבני-אדם.
• לכן:
;)Student s = new Student("shlomo",124
;Comparable c = s
או למשל,
;)Comparable c = new Student("shlomo",124
21
:שימו לב כי לא ניתו ליצור אובייקט מטיפוס ממשק
Comparable c = new Comparable();
. ולא מחלקה, היא בסה"כ תכונהComparable – הסיבה היא פשוטה
public static void func(Comparable c){…}
Car car1 = new Car(2004, "Toyota");
Comparable car2 = new Car(1990, "Mercedes");
Point p = new Point(1,1);
Object car3 = new Car(1982, "Lada");
func(car2);
func(car1);
func(p);
func(car3);
func((Comparable) car3);
func((Comparable) p);
Car3 = p;
22
func((Comparable)
car3);
•
•
Sorting both Students and Cars
public static void main(String[] args) {
Student[] myStudents = new Student[2];
myStudents[0] = new Student(2, "Vika");
myStudents[1] = new Student(1, "Dan");
System.out.println(arr2String(myStudents));
insertionSort(myStudents);
System.out.println(arr2String(myStudents));
Car c1 = new Car(2004, "Toyota");
Car c2 = new Car(1990, "Mercedes");
Car[] myCars = {c1,c2};
System.out.println(arr2String(myCars));
insertionSort(myCars);
System.out.println(arr2String(myCars));
}
23
:עכשיו נחזור למיון
public static void insertionSort(Comparable[]
array){
Comparable value;
for (int i=1; i < array.length; i = i+1){
value = array[i];
int j = i;
while(j>0 &&
array[j-1].compareTo(value) > 0){
array[j] = array[j-1];
j = j-1;
}
array[j] = value;
}
}//insertionSort(Comparable[] array)
24
נקודות נוספות לדיון ומחשבה:
•
•
•
•
•
הממשק שהגדרנו קיים בחבילה (,java.lang )package
וחלק מהמחלקות המובנות ב java-מממשות אותו (למשל
.)String
אילו שיטות ניתן להפעיל על עצם? לפי הטיפוס של
המצביע ,אלא אם כן עשינו .casting
ממשק יכול להגדיר יותר משיטה אחת.
מחלקה יכולה לממש יותר ממשק אחד:
public class Car implements
}…{Comparable, Vehicle
ממשקים והנדסת תוכנה – אינטגרציה ,תיקון באגים,
חשיבה עתידית וגמישות.
25
כמובן שבאותו.InsertionSort • ראינו מימוש של
. וכוMergeSort, BubbleSort האופן קיימים
• נניח שנרצה למיין במספר אופנים שונים בתוכנית
.שלנו
?• היכן נמקם את השיטות הללו? במחלקה אחת
public class sortAlgorithms{
public static void InsertionSort(Comparable[] arr);
public static void MergeSort(Comparable[] arr);
…
}
26
Sorter
public interface Sorter{
public void sort(Comparable[] array);
}
כל מי שרוצה להוסיף שיטת מיון חדשה צריך,עכשיו
:Sorter פשוט לממש את הממשק
27
class InsertionSorter implements Sorter{
public void sort(Comparable[] array){
…
}
}//class
class MergeSorter implements Sorter{
public void sort(Comparable[] array){
…
}
}//class
28
:דוגמה
Sorter s1= new InsertionSorter();
Student[] sArr=new Student[2];
sArr[0]=new Student(2352452,"david");
sArr[1]=new Student(111252,"Anat");
s1.sort(sArr);
Sorter s2= new MergeSorter();
Car[] cArr=new Car[2];
cArr[0]=new Car(2004,"toyota");
cArr[1]=new Car(1943,"Ford");
s2.sort(cArr);
29
Interface Replicable
מוטיבציה
y
y
)(getX
)(getY
x
)(getX
)(getY
x
y
x
)(getX
)(getY
מצב בלתי חוקי – שני עצמים זהים
)לפי שיטת equalsשלהם) בקבוצה.
נובע מכך ששמרנו בadd-
מצביע לאובייקט המקורי
30
public void add(Object o){
if ((o != null) && !contains(o) &&
(size<elements.length)){
elements[size] = o;
size = size + 1;
}
}//add
31
Interface Replicable
מוטיבציה
y
y
)(getX
)(getY
x
)(getX
)(getY
x
y
x
)(getX
)(getY
נרצה שבקבוצה יאוכסנו רק עותקים של
העצמים .שאפשר יהיה להגיע אליהם רק
דרך השיטות של הקבוצה.
מה הבעיה? new Objectלא ייצור את האובייקט
שאני באמת רוצה – בזמן ריצה
32
public void add(Object o){
if ((o != null) && !contains(o) &&
(size<elements.length)){
elements[size] = new Object(o);
size = size + 1;
}
}//add
33
Replicable
- אשר כל מי שמממש אותו הוא "בר,Replicable • נגדיר ממשק
לממשק זה תהיה שיטה אחת בלבד אשר תחזיר עותק."הכפלה
:של האובייקט
public interface Replicable {
/**
* @return a replicate of this object.
*/
public Object replicate();
}
34
:Point נסתכל לדוגמה על המחלקה
public class Point implements Replicable {
…
public Object replicate(){
return new Point(this);
}
}
35
ReplicableObjectSet
• וכעת נגדיר מחלקה .ReplicableObjectSet
מחלקה זו תהיה זהה לחלוטין למחלקה
,ObjectSetאך תכלול שני הבדלים:
– במקום לקבל בשיטה addפרמטר מסוג Objectנקבל
פרמטר מסוג .Replicable
– הקבוצה תחזיק עותקים של האוביקטים שהכנסנו
אליה ,ולא את המקוריים .לגורמים חיצוניים לא תיהיה
גישה ישירה אל אברי הקבוצה.
36
ReplicableObjectSet
public class ReplicableObjectSet {
…
public void add(Replicable o){
if ((o != null) && !contains(o) &&
(size<elements.length)){
elements[size] = o.replicate();
size = size + 1;
}
}//add
37