לקראת המעבר לשפות תכנות מונחה עצמים

התאמת תכנית הלימודים ביסודות עם המעבר לשפות מנחות עצמים

הוכן ע"י יעל סופרין והילה קדמן

החומרים שלפניכם הוכנו על ידי משתתפי סמינר קיץ למורים מובילים תשס"ד.

שימו לב: לא ניתן לעשות בחומר הזה כל שימוש מסחרי ללא רשות בכתב מראש מיוצרי החומרים.

 

מבנה העבודה:

הדילמה:              כיצד ניתן לשנות את שפת הלימוד במדעי המחשב, משפה פרוצדוראלית לשפה מונחית עצמים, עם שינויים מינימאליים בתכנית הלימודים.

הפשטות:            מעבר ל-java ו- C#  -  הדגמה עד כמה פשוט יהיה המעבר דרך שאלה 6 מבגרות תשס"ה.

הבעייתיות:          נושא המבנים – הדגמת הבעייתיות על ידי שאלה 10 מבגרות תשס"ה (הדורשת מבנים).

                        נושא הפונקציות – הדגמת הבעייתיות על ידי פישוט שאלה 10 מבגרות תשס"ה.

בעיות נוספות:      מספר בעיות נוספות הנצפות על ידינו לקראת המעבר לשפות מונחות עצמים.

 

 הדילמה:

המעבר משפות פרוצדוראליות לשפות מונחות עצמים מעורר תהייה: מה צריך ללמד באיזו דרך.

דרך I  -  המשך ההוראה בגישת יסודות תוך שינוי סביבת העבודה בלבד – זו הדרך הנבדקת כיום.

דרך II -  שינוי הפרדיגמה התכנותית מתכנות פרוצדוראלי לתכנות OOP – על דרך זו ברצוננו לדון   בעבודה  זו.

 

הפשטות:

ברמה הפשוטה של פתרון בעיות אלגוריתמיות, ניתן לבצע את אותו האלגוריתם בדיוק, אך במקום כתכנית עצמאית, כאלגוריתם בתוך הפונקציה הראשית – הסטטית אשר קיימת בכל אובייקט.

נדגים זאת על ידי בעיית המבוך (שאלה 6 מבגרות תשס"ה), אותה ניתן למצוא בנספח א'.


הבעייתיות
:

ברגע שמגיעים לבעיה מורכבת יותר, הדורשת סימולציה של המציאות – נכנס לתמונה היבט נוסף אשר משמעותי בתכנות מונחה עצמים.

אם נלמד את התלמידים עקרונות כפי שלמדנו עד היום - עקרונות המנחים תכנות פרוצדוראלי (פונקציות המקבלות פרמטרים) במקום את העיקרון המנחה תכנות מכוון עצמים (פונקציות העובדות על מאפייני אובייקט). נלמד אותם תכנות שאיננו נכון, ואחר כך נצטרך לעבוד קשה כדי לתקן את הטבוע בזיכרונם כשיעברו לעיצוב ויחידה חמישית ב- OOP.

לדעתנו, האופן הנכון ללמד את הדברים הינו ללמד ביסודות את הנושאים: מהו עצם, ומה תפקידו, וכיצד נכתוב עצם בודד.

נדגים זאת על ידי בעיית המבחן הארצי, (שאלה 10 מבגרות תשס"ה), אותה ניתן למצוא בנספח ב'.

בעיה זו עוסקת בתחרות ארצית ודורשת יצירת מבנה (רשומה) לצורת שמירת נתוני תלמיד, שמירה של כמה מערכים המכילים מידע על מתמודדים, ומעבר על מערכים אלו לצורך חישוב ממוצע, מיון מצטיינים והדפסת נתוני המצטיינים.

בבעיה זו נוכל להבחין במספר דילמות העולות:

1. בשפת JAVA – לא קיים כלל מושג המבנה. האפשרות היחידה הינה יצירת אובייקט נוסף פרט לאובייקט בו נמצאת הפונקציה הראשית. ניתן ליצור אובייקט זה באופן מלאכותי כך שכל תכונותיו יהיו משותפות (public), אך באופן זה אנו מלמדים את תלמידינו תכנות שאינו נכון, ויבלבל אותם מאוד כאשר ילמדו את עקרונות התכנות מונחה העצמים.

בשפת C# - קיים מושג המבנה.

2. נפשט את הבעיה. נניח כי לא נתבקשנו לשמור את המידע על התלמידים אלה את ציוניהם בלבד. באופן זה – עלינו לשמור מערכים המכילים מספרים שלמים, כך שבעיית המבנים אינה קיימת עוד. את הבעיה הזו ניתן לראות משתי נקודות מבט שונות.
האחת – כסדרת הוראות הפועלות צעד אחר צעד כמודגם באלגוריתם לפיתרון.
השנייה – כבעיה המציגה תחרות, ומצפה שהאובייקט תחרות הוא זה שיפתור אותה.
( שתי גישות אלו מוצגות בנספח ב' ).
אם נציג לתלמיד בעיות סימולציה, אך לא נטרח להראות לתלמיד את היבט מונחה העצמים של הפתרון – נלמד אותו דרך פתרון אשר אינה הולמת שפה מונחת עצמים, ולא לכך היא נועדה. וברגע שיתחיל התלמיד את לימודי עיצוב התכנה – הבלבול יהיה רב. לא ניתן לצפות מתלמיד שיבין בשנה אחת אופן תכנותי מסוים, ובשנה לאחר מכן – לסתור אופן זה וללמד אותו אופן שונה.
אם נלמד את התלמידים בשיטת יסודות - פירוק כל בעיה לתת-בעיות וטיפול בכל תת-בעיה בנפרד, תיווצר אצלם בעיה דומה ויתקבל  "תכנות
OOP עם מבטא פרוצדוראלי".
ההבדל נעוץ בעצם באחריות על הפעלת השגרות. האם התכנית הראשית היא זו שמפעילה את השגרות כפי שהתרגלנו בתכנות הפרוצדוראלי, או שהאובייקט תחרות הוא זה שמנהל את התכנית ומפעיל את השגרות – אשר בעצם משויכות אליו.

לבעיות אלו אנו רואות שתי פתרונות אפשריים:

*  הוראה בשפה מונחת עצמים ללא אובייקטים, ומכך - ללא סימולציות. יש לציין כי רמת הלימוד, אפקטיביות של המקצוע ומידת העניין שיביעו התלמידים באופן זה יורדת, לדעתנו, באופן משמעותי בפתרון זה.

*  הוראת OOP "אמיתי", בו התלמיד ילמד לאבחן את האובייקט שבבעיית הסימולציה, את תכונותיו, את פעולותיו, כך שהאובייקט הוא זה שיפעיל את הפונקציות של עצמו (הפעולות / שיטות) שלו.

על פי כך, לתכנית הלימודים שתי אפשרויות לארגון מחדש:

·               לפי הגישה האומרת שינוי בשפה בלבד:

יסודות – אלגוריתמיקה, קלט/פלט, מחרוזות, מבני בקרה, מערכים חד-ממדיים ודו-ממדיים. פונקציות static תוך הקפדה של הפעלתן על טיפוסים פשוטים בלבד (ללא סימולציות).

עיצוב תכנה – מחלקות, אובייקטים, שילוב של אובייקטים והתקשורת ביניהם.
מבני נתונים מתקדמים.

יחידה 5 - OOP – הורשה ופולימורפיזם.

·               לפי הגישה של שינוי בפרדיגמה התכנותית:

יסודות – אלגוריתמיקה, קלט/פלט, מחרוזות, מבני בקרה, מערכים חד-ממדיים ודו-ממדיים.
אובייקט מהו, שימוש באובייקט יחיד.

עיצוב תכנה – שילוב של אובייקטים והתקשורת ביניהם. מבני נתונים מתקדמים.

יחידה 5 - OOP – הורשה ופולימורפיזם.

 

בעיות נוספות:

בנוסף, ברצוננו להציג מספר בעיות נוספות אשר, לדעתנו, יש לתת עליהם את הדעת לקראת המעבר הצפוי לשפות התכנות החדשות.

·               קושי שנובע ממבנה התכנית:
התכנית הבסיסית כוללת מלל רב, ובבחינת הבגרות נדרש התלמיד לכתוב 3-5 תכניות.
דבר זה מייגע למדי ויצרך זמן רב מהתלמידים העת בחינה.
מבנה התכנית ב-
java:

public class mainClass
{
            public static void main(String[] args)
            {
                       
            }
 }

מבנה התכנית ב- C#:

using System;
class MainClass
{
           
public static void Main(string[] args)
            {
                       
           
} 
}

 

·               קושי שנובע מהוראות קלט/פלט "ארוכות".
בעייתי במיוחד לתלמידים אשר שפת האם שלהם אינה אנגלית.
בשפת
java :

x = InputRequestor.requestDouble (“…”);
OutputWindow.print(“…”);      
                                     

 בשפת C#:

x = int.Parse(Console.ReadLine());       
Console.WriteLine(“…”);                        

 

·               קושי שנובע מסביבת העבודה:
בשתי השפות, סביבת העבודה מורכבת יותר. נדרש יצירת פרויקט חדש עבור כל עבודה. נדרש להוסיף מחלקה קיימת לפרויקט.
על התלמיד להיות בקי ברזי סביבת העבודה בנוסף לכל שאר מחויבויותיו למקצוע.

 

נספח א' - בעיית המבוך (שאלה 6 מבגרות תשס"ה)

בגן משחקים יש כניסה המובילה לשני מבוכים:  big  ו-  small.
המבוך
big מיועד לאנשים שגובהם 1.70 מ' ומעלה, והמבוך small מיועד לאלה שגובהם פחות מ-1.70 מ'.
כתוב תכנית שתקלוט את הגובה של כל אחד מהאנשים המגיעים לכניסה, ותדפיס את שם המבוך שאליו ייכנס. התכנית תמנה ותדפיס את מספר האנשים שנכנסו לכל אחד מהמבוכים ביום מסוים.

קליטת הגבהים של האנשים תסתיים כאשר ייקלט הגובה 0.

 

האלגוריתם לפיתרון:

 (1)       איפוס מונים: countBig ¬ 0, countSmall ¬ 0 

(2)        קלט: גובה מבקר ¬  height
(3)        כל עוד  height ≠ 0, בצע
            (3.1)     אם height ≥ 1.70  - 
                        (3.1.1)  הדפס “big”
                        (3.1.2)  הגדל את countBig ב- 1
            (3.2)     אחרת - 
                        (3.2.1)  הדפס: “small”
                        (3.2.2)  הגדל את countSmall ב-1
           
(3.3)      קלט: גובה מבקר ¬  height

(4)        הצג כפלט את ערכי המונים.

 

התכנית בשפות מונחות עצמים:

JAVA

public class Maze

{

            public static void main(String[] args)

{

                        int countBig=0, countSmall=0;

                        double height;

                       

                        height = InputRequestor.requestDouble ("\n"+"Enter Your Height ");

                        while (height != 0)

{

                                    if (height >= 1.7)

{

                                                OutputWindow.print(height+"  Big"+"\n");

                                                countBig++;

                                    }

                                    else

{

                                                OutputWindow.print(height+"  Small"+"\n");

                                                countSmall++;

                                    }

                                    height = InputRequestor.requestDouble ("\n"+"Enter Your Height ");

                        }                                 

                        OutputWindow.println ("\n"+" big -  "+countBig);         

                        OutputWindow.println ("small -  "+countSmall);                        

            }         

}

C#

public class maze

{

            static void Main (string[] args)

{         

                        int countBig=0, countSmall=0;

                        float height;

           

                        Console.WriteLine("Enter Your Height (0 to finish)");

                        height = float.Parse(Console.ReadLine());

                        while (height != 0) 

{

                                    if (height >= 1.7) 

{         

                                                Console.WriteLine("{0} Big", height);

                                                countBig++;

                                    }

                                    else 

{

                                                Console.WriteLine("{0} Small", height);

                                                countSmall++;

                                    }

                                    Console.WriteLine("Enter Your Height (0 to finish)");

                                    height = float.Parse(Console.ReadLine());

                        }

                       

                        Console.WriteLine("big - {0}",countBig);         

Console.WriteLine("small - {0}",countSmall);  

            }

}

 

נספח ב' - בעיית המבחן הארצי, (שאלה 10 מבגרות תשס"ה)

לקראת תחרות ארצית במדעי המחשב, נערכה בחינת מיון ל- 1750 תלמידים.
לתחרות הארצית יתקבלו תלמידים שציוניהם בבחינת המיון גבוה מהציון הממוצע של כל הנבחנים בבחינה זו.

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

האלגוריתם יציג כפלט שתי רשימות המכילות את שמות התלמידים שיתקבלו לתחרות הארצית, כתובותיהם ומספרי תעודות הזהות שלהם.

הרשימה הראשונה תכלול את פרטי התלמידים ששפת התכנות שלהם היא פסקל, והרשימה השנייה תכלול את פרטי התלמידים ששפת התכנות שלהם היא C.

 

האלגוריתם לפיתרון:

(1)        קלט למערך הכללי
(2)        חישוב הציון הממוצע בבחינה  ¬ avg
(3)        העברת כל התלמידים שציונם גבוה מ-avg ושפת התכנות שלהם היא פסקל, למערך מצטייני-פסקל.
(4)        העברת כל התלמידים שציונם גבוה מ-avg ושפת התכנות שלהם היא C, למערך 
            מצטייני-
C.
)
5)        הדפסת אברי מערך מצטייני-פסקל.
(6)        הדפסת אברי מערך מצטייני-C.

 

גישה פרוצדורלית (C#)

using System;

namespace Ex10C  {

            class contest  {

                        struct StudentsDetails {

                                    public String name, addr;

                                    public long id;

                                    public char progLan;  //'c' = C language, 'p' = pascal

                                    public double avg;

 

                                    //--- Student constructor

                                    public StudentsDetails (String name, String addr, long
                                                                                    id,        char progLan, double avg)

{

                                                this.name = name;

                                                this.addr = addr;

                                                this.id = id;

                                                this.progLan = progLan;

                                                this.avg = avg;

                                    }

 

                        }

 

                        static void Main(string[] args)

                        {

                                    StudentsDetails[] arrGeneral, arrC, arrPas;

                                    double average;

                                    int i, countC= 0, countPas= 0;

                       

                                    arrGeneral = new StudentsDetails[ARR_SIZE];

                                    arrC = new StudentsDetails[ARR_SIZE];

                                    arrPas = new StudentsDetails[ARR_SIZE];

                       

                                    arrInput(arrGeneral);

                       

                                    average = gradeAvg(arrGeneral);

                       

                                    //--- split general array to C and Pascal array ---

                                    for(i=0 ; i<ARR_SIZE ; i++)

                                                if (arrGeneral[i].avg>average)

                                                            if(arrGeneral[i].progLan == 'c')

                                                                        arrC[countC++] = arrGeneral[i];

                                                            else

                                                                        arrPas[countPas++] = arrGeneral[i];

                                                           

                                    arrOutput(arrC, countC, 'c');

                                    arrOutput(arrPas, countPas, 'p');

 

                                    arrGeneral = null;

                                    arrC = null;

                                    arrPas = null;

                        }

 

                        //---  input data to general array ---

                        static void arrInput (StudentsDetails[] arr)

                        {

                                    int i;                 

                                    for(i=0 ; i<ARR_SIZE ; i++)

                                    {

                                                String name, addr;

                                                long id;

                                                char progLan;

                                                double avg;

                                   

                                                //--- input data ---

                                                Console.WriteLine("Student #{0}: ",i+1);         

                                                Console.Write("Enter name: ");

                                                name = Console.ReadLine();                           

                                                Console.Write("Enter adrress: ");

                                                addr = Console.ReadLine();                            

                                                Console.Write("Enter id: ");

                                                id = int.Parse(Console.ReadLine());

                                                Console.Write("Enter program language: ");

                                                progLan = char.Parse(Console.ReadLine());    

                                                Console.Write("Enter average grade: ");

                                                avg = double.Parse(Console.ReadLine());                    

                                   

                                                //--- constructing student's record ---

                                                arr[i] = new StudentsDetails(name, addr, id,
                                                                                                                        progLan, avg);

                                                Console.WriteLine("");

                                    }

                        }

                       

                        //---  output general array as is  ---

           

                        //--- output Pascal or C arrays ---

                        static void arrOutput(StudentsDetails[] arr, int n, char lang)

                        {

                                    int i;

                                    if(lang == 'c')

                                                Console.WriteLine("List of C contester:");

                                    else

                                                Console.WriteLine("List of Pascal contester:");

                       

                                    for(i=0 ; i<n ; i++)  {

                                                Console.WriteLine("Student #{0}",i+1);                                                                       Console.WriteLine("name: {0}",arr[i].name);

                                                Console.WriteLine("adrress: {0}",arr[i].addr);                          

                                                Console.WriteLine("ID: {0}",arr[i].id); 

                                                Console.WriteLine();

                                    }

                        }

           

                        //--- returns general array grade average ---

                        static double gradeAvg(StudentsDetails[] arr)

                        {

                                    double sum=0;

                       

                                    for(int i=0 ; i<ARR_SIZE ; i++)           

                                                sum = sum + arr[i].avg;

                                    return sum/ARR_SIZE;

                        }

 

                        const int ARR_SIZE = 5;

 

            }//end of class Contest

}

 

גישת OOP, C#

using System;

            public class StudentsArr   {

                        struct StudentDetails 

{

                                    public String name, addr;

                                    public long id;

                                    public char progLan;   // 'c' = C language, 'p' = pascal

                                    public float avg;

 

                                    public void SetDetails (String name, String addr, long
                                                                                    id,        char progLan, float avg)

                                    {

                                                this.name = name;

                                                this.addr = addr;

                                                this.id = id;

                                                this.progLan = progLan;

                                                this.avg = avg;

                                    }

 

                        }

                        public StudentsArr()

                        {

                                    Arr = new StudentDetails[ARR_SIZE];

                                    ArrRef = 0;

                        }

 

                        public void AddStudent(String name, String addr, long id, char
                                                                                                            progLan, float avg)

                        {

                                    Arr[ArrRef++].SetDetails(name, addr, id,progLan, avg);

                                    ArrAvSum += avg;

                        }

 

                        void AddStudent(StudentDetails stu)

                        {

                                    AddStudent(stu.name, stu.addr, stu.id, stu.progLan,
                                                                                                                        stu.avg);

                        }

 

                        public float GetArrAv()

                        {

                                    return ArrAvSum / ArrRef;

                        }

 

                        public void Print()

                        {

                                    for(int i=0 ; i<ArrRef ; i++)

                                    {

                                                Console.WriteLine("Student #{0}",i+1);                      

                                                Console.WriteLine("name: {0}",Arr[i].name);   

                                                Console.WriteLine("adrress: {0}",Arr[i].addr); 

                                                Console.WriteLine("ID: {0}",Arr[i].id);            

                                                Console.WriteLine();

                                    }

                        }

 

                        public static int getArrSize()

                        {

                                    return ARR_SIZE;

                        }

 

                        public void CopyStudentAboveAv(StudentsArr StuArr, float av,
                                                                                                                        char progLan)

                        {

                                    for(int i=0 ; i<ARR_SIZE ; i++)

                                                if (Arr[i].avg > av && Arr[i].progLan == progLan)

                                                            StuArr.AddStudent(Arr[i]);

                        }

 

                        StudentDetails[] Arr;

                        int ArrRef;

                        float ArrAvSum;

                        const int ARR_SIZE = 5;

            } //end of class StudentsArr

 

 

class contest

            {

                        static void Main(string[] args)

                        {

                                    contest con = new contest();

                                    con.init();

                                    con.SetStudentsDetails();

                                    con.Choose();

                                    con.printChosen();

                        }

           

 

                        void init()

                        {

                                    arrGeneral = new StudentsArr();

                                    arrC = new StudentsArr();

                                    arrPas = new StudentsArr();

                        }

 

                        //---  input data to general array ---

                        void SetStudentsDetails ()

                        {                     

                                    int ArrSize = StudentsArr.getArrSize();

                                    for(int i=0 ; i<ArrSize ; i++)

                                    {

                                                String name, addr;

                                                long id;

                                                char progLan;

                                                float avg;

                                   

                                                //--- input data ---

                                                Console.WriteLine("\nStudent #{0}: ",i+1);      

                                                Console.Write("Enter name: ");

                                                name = Console.ReadLine();                           

                                                Console.Write("Enter adrress: ");

                                                addr = Console.ReadLine();                            

                                                Console.Write("Enter id: ");

                                                id = int.Parse(Console.ReadLine());

                                                Console.Write("Enter program language: ");

                                                progLan = char.Parse(Console.ReadLine());    

                                                Console.Write("Enter average grade: ");

                                                avg = float.Parse(Console.ReadLine());            

                                   

                                                //--- constructing student's record ---

                                                arrGeneral.AddStudent(name, addr, id, progLan,
                                                                                                                                    avg);

                                    }

                        }

                       

                        public void Choose()

                        {

                                    float average;

                                               

                                    average = arrGeneral.GetArrAv();

                       

                                    //--- split general array to C and Pascal array ---

                                    arrGeneral.CopyStudentAboveAv(arrC, average, 'c');

                                    arrGeneral.CopyStudentAboveAv(arrPas, average, 'p');

                        }

 

                        void printChosen()

                        {

                                    Console.WriteLine("\nList of C contester:");

                                    arrC.Print();

                                    Console.WriteLine("\nList of Pascal contester:");

                                    arrPas.Print();

                        }

 

 

                        StudentsArr arrGeneral, arrC, arrPas;

            }//end of class Contest

 

 

חזרה לעמוד הראשי