תכנות מונחה-עצמים

תכנות מונחה־עצמים או לעיתים תכנות מוכוון־עצמיםאנגלית: Object-Oriented Programming, או בקיצור OOP) הוא פרדיגמת תכנות המשתמשת ב"עצמים" (אובייקטים) לשם תכנות תוכניות מחשב.

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

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

הפרדיגמה היוותה מהפכה בכתיבת תוכנה והחלה לשמש בפיתוח תוכנה החל מתחילת שנות ה־80 של המאה ה־20 ואילך, אך השימוש בפרדיגמה בשלמותה החל רק בשנות ה־90. רוב שפות התכנות המודרניות תומכות בתכנות מונחה־עצמים.

תכנות מונחה־עצמים הוא חלק מתפיסה (פרספציה) של פיתוח מונחה־עצמים, הכולל גם ניתוח מערכות מונחה־עצמים (OOA), עיצוב מונחה־עצמים (OOD) ובמידה חלקית גם מסדי נתונים מונחי־עצמים (Object-Oriented Databases).

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

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

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

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

היסטוריה

עריכה

הרעיון של עצמים ומופעים שלהם הופיע לראשונה בשנת 1963 בתוכנה בשם Sketchpad.

כמתודולוגיה לפיתוח תוכנה, מומש תכנות מונחה־עצמים לראשונה בשפת הסימולציה Simula 67, שנוצרה בשנות ה-60 של המאה ה-20 על ידי הנורווגים אולה־יוהאן דאל וקריסטן ניגארד. בשנת 2001 הוענק לשניים פרס טיורינג, בזכות תרומתם לפיתוחו של תכנות מונחה־עצמים. השפה מימשה למעשה סוג פרימיטיבי של סגור, שהוא תכונה של שפות תכנות המאפשרת התנהגות דומה לזאת של אובייקט.

פיתוח ושכלול של הרעיון נעשו בשפת Smalltalk, שפותחה בשנות ה-70 של המאה ה-20 בזירוקס פארק. שפה זו זכתה להכרה נרחבת ולעניין רב באקדמיה ובתעשייה, והייתה השפה הראשונה שניתן לכנותה "מונחית־עצמים".

בפיתוח תוכנה עסקית זכתה מתודולוגיה זו לתפוצה רחבה החל מסוף שנות ה־80 של המאה ה-20, תחילה ב־Smalltalk ולאחר מכן בשפות התכנות C++‎ וטורבו פסקל. שפת אייפל שהוכרזה ב־1985 הושפעה מהשפות פסקל, Simula, ‏Ada‏, Z ושימשה השראה לשפות פופולריות כמו #C ‏,Java ‏,ו־Ruby‏.

שפות נוספות התומכות בתכנות מונחה־עצמים הן פייתון, Ruby ,Delphi ועוד רבות אחרות.

במסגרת יוזמת NET. של חברת מיקרוסופט פיתחה החברה שפה חדשה לתכנות מונחה־עצמים, #C, והשלימה יכולת זו שהייתה חלקית בגרסה שישית של שפת Visual Basic, בגרסה הקרויה Visual Basic .NET.

מהות הפרדיגמה וטרמינולוגיה

עריכה

מרכיב בסיסי בתכנות מונחה־עצמים הוא המחלקה (Class). מחלקה היא מבנה מופשט בעל שדות (fields) המגדירים את המחלקה כלפי פנים, תכונות (Properties) המגדירות ומאפיינות את המחלקה כלפי חוץ, ושיטות (Methods) שהן פונקציות ייחודיות למחלקה, הפועלות על משתני המחלקה. בחלק משפות התכנות (בעיקר המודרניות כמו Java ו־#C ו PHP) קיימים גם אירועים (Events), שהם הודעות השייכות למחלקה ומוזנקות בהקשרים שונים, למשל בתחילתו או בסיומו של הליך או כתגובה לקלט מהמשתמש.

על מנת להשתמש במחלקה, המתכנת יוצר מופעים שלה. כל מופע של מחלקה הוא עצם (Object או Instance). היחס בין המחלקה לבין המופע, הוא היחס בין הגדרת טיפוס (Type) לבין הכרזת משתנה מסוג טיפוס בפועל בזיכרון המחשב. כלומר, בעוד שהמחלקה מהווה תבנית ומגדירה את התכונות והפעולות השייכות לה, עצם הוא משתנה פעיל שטיפוסו הוא המחלקה ומכיל את המידע הזה בפועל - כל עצם מכיל את התכונות והפעולות שהוגדרו במחלקה ממנה נוצר. לדוגמה, למחלקה הקרויה "מכונית" יש תכונות: צבע, דגם, שנת יצור, ופעולות: התנעה, נסיעה, עצירה. כל מכונית מסוימת היא עצם במחלקה זו, ולכל תכונה ערך המתאים למכונית המסוימת, למשל מזדה לבנה מודל 2003.

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

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

מאפיינים

עריכה

אין הסכמה כללית לגבי סט מסוים של תכונות המגדירות מהו תכנות מונחה־עצמים, או מהי שפה מונחית־עצמים. חוקרים שונים מגדירים מאפיינים שונים, ושפות שונות תומכות במאפיינים שונים. כאשר כל מאפיין בנפרד מופיע גם בפרדיגמות תכנות אחרות:[1]

  • הפשטת נתונים (Data Abstraction) הנעשית באמצעות כימוס (Encapsulation) והסתרת המידע (Information Hiding) - הסתרה של מימוש. הפשטת הנתונים מתממשת בשפה באמצעות הגדרות מופשטות של מבנה הנתונים במחלקה, שלאחר מכן יכולים להיות להם מופעים קונקרטיים כאובייקט.
  • כימוס (Encapsulation) - הסתרת המבנה הפנימי של המחלקה ממי שמשתמש בה.
  • היררכיה הגדרת יחסים היררכיים בין עצמים באמצעות:
    • ירושה (Inheritance) - ירושה של מימוש של מתודות או משתנים. מחלקה היורשת ממחלקה אחרת מעניקה לאובייקטים שלה גם את המימוש הפנימי של המחלקה האחרת. כאשר מדובר בירושה ציבורית (כמו ברוב שפות התכנות), היא מגיעה בד בבד עם הגדרה של המחלקה החדשה כתת־טיפוס של הראשונה.
    • פולימורפיזם של תת־טיפוסים (Subtyping) - טיפוס א' הוא תת־טיפוס של טיפוס ב' אם כל הממשק של ב' ממומש באובייקט א'. במקרה כזה, כל פעולה שניתן לבצע על אובייקט מטיפוס ב' ניתן לבצע גם על אובייקט מטיפוס א' - כולל העברה כפרמטר לפונקציות, או הפעלה של מתודות.
  • ריבוי ייצוגים או הפעלה דינמית (Multiple representations או Dynamic dispatch) - כאשר מבוצעת על אובייקט פעולה, האובייקט עצמו בוחר את המימוש שיבצע את הפעולה. זהו המאפיין העיקרי המבדיל בין אובייקטים לבין ADT - טיפוסי נתונים מופשטים.
  • מודולריות (Modularity) - חלוקת העצמים (האובייקטים) לפי נושא, הפרדה לתחומים שונים, וקיבוץ תכונות ושיטות ליחידות בעלות נושא או עניין אחד, אשר כל אחת מהן מהווה יחידה עצמאית וסגורה כמו בעולם הממשי.
  • רקורסיה פתוחה (Open recursion) או חיפוש דינמי (Dynamic lookup) של מתודות. קיים משתנה מיוחד (או מילה שמורה) בשם this, self או Me, המאפשר לגוף של מתודה לקרוא למתודה אחרת על אותו אובייקט. המזהה של המשתנה נכרך בזמן ריצה (Late binding) - מה שמאפשר למתודות של מחלקה אחת להפעיל מתודות שהוגדרו אחריה, במחלקה שירשה ממנה. ישנן שפות התומכות במנגנון מורחב יותר הנקרא Multi-methods.

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

הפשטת נתונים

עריכה

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

בדוגמה הבאה בשפת ג'אווה, נעשית הדגמה בהגדרה מופשטת מחלקת בעל חיים Animal, שיש לה את התכונות "מיקום", ו"מאגרי אנרגיה", ואת השיטות: "האם רעב", "לאכול", ו"לנוע".

public class Animal extends LivingThing
{
     private Location loc;
     private double energyReserves;

     public boolean isHungry() {
         return energyReserves < 2.5;
     }
     public void eat(Food food) {
         // Consume food
         energyReserves += food.getCalories();
     }
     public void moveTo(Location location) {
         // Move to new location
         this.loc = location;
     }
}

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

thePig = new Animal();
theCow = new Animal();
if (thePig.isHungry()) {
    thePig.eat(tableScraps);
}
if (theCow.isHungry()) {
    theCow.eat(grass);
}
theCow.moveTo(theBarn);

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

כימוס

עריכה
  ערך מורחב – כימוס

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

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

    class Vehicle
    {
        Engine engine = new Engine();
        Gear gear = new Gear();
        GasPump gasPump = new GasPump();
        Handbrake handbrake = new Handbrake();

        public void StartDriving(int gearNum)
        {
            engine.TurnOn();
            gear.TransferGear(gearNum);
            handbrake.SetStatus(false);
            gasPump.FuelInject(20.55F);
        }
    }

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

ישנן שפות תכנות מונחות־עצמים שאינן מאפשרות כימוס, או מאפשרות להפר אותו:

  • בגרסאות ישנות בשפת פייתון, אין דרך למנוע גישה אל כל שדה של כל אובייקט, וניתן רק לסמן שדות שאינם מיועדים לגישה כזאת על ידי מתן שם מתאים. עם זאת, בגרסאות חדשות ניתן להגדיר משתנה מחלקה בשם המתחיל בשני קווים תחתונים והוא ישמש כמשתנה פרטי.
  • בשפות ++C, ג'אווה, #C ודומותיהן ניתן להצהיר על שדות "ציבוריים", שניתנים לגישה מכל מקום.
  • בשפת ++C ניתן להצהיר על מחלקה "חברה" (Friend) או פונקציה חברה, הרשאית לגשת לכל שדה באובייקט, גם אם הוגדר כפרטי.
  • תכונת ההתבוננות־פנימה (Reflection) בשפת ג'אווה מאפשרת לגשת לכל שדה בכל אובייקט.

תת־טיפוסים

עריכה

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

אם אובייקט יכול לבצע קבוצה של פעולות, הוא שייך גם לכל טיפוס שדורש רק חלק מהפעולות האלה. היכולת להתעלם מחלק מהממשק של אובייקט מאפשר לכתוב קטע קוד יחיד המאפשר לבצע מניפולציה על מגוון רחב של אובייקטים, תוך שהוא דורש רק את הממשק המשותף שלהם. תכונה זו מנוצלת במיוחד בשפות בעלת טיפוסיות ברווז כגון פייתון, Ruby, ו־Smalltalk. ממשקים (Interface) בשפת ג'אווה ומחלקות אבסטרקטיות בשפת ++C מאפשרים גם הם להגדיר במפורש תתי־טיפוסים, בלי צורך לבצע ירושה (ראו בהמשך) של המימוש.

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

תמיכה לתת־טיפוסים בשפה מסייעת בשימוש בפולימורפיזם.

ירושה

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

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

ניתן להגדיר מחלקה חדשה על בסיס מחלקה קיימת. למחלקה החדשה ישנן כל התכונות והפעולות שירשה מהמחלקה שלפיה הוגדרה, ובנוסף ניתן להגדיר פעולות נוספות במחלקה החדשה, או לשנות פעולות שירשה. המחלקה המורישה קרויה מחלקת בסיס (base class), מחלקת־אב (parent) או מחלקת־על (superclass). המחלקה היורשת קרויה מחלקה נגזרת (derived class), בן (child) או תת־מחלקה (subclass).

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

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

ישנן שפות שבהן ניתן לרשת בו זמנית מכמה מחלקות בסיס, וליצור מחלקה שממזגת את התכונות של כמה מחלקות; ירושה כזאת עלולה ליצור בעיות במקרה של "ירושת יהלום", כלומר מקרה בו שתיים ממחלקות הבסיס יורשות מאותה מחלקה. בשל כך חלק מהשפות מגבילות את המנגנון לירושה ממחלקת בסיס אחת, ומימוש מספר ממשקים.

פולימורפיזם

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

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

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

ריבוי ייצוגים

עריכה

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

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

מבנה דוגמת תוכנית מונחת עצמים

עריכה
  • פרויקט1
    • מחלקה 1
      • הגדרת שדות ושיטות למחלקה 1
      • מחלקה 1א: יורשת ממחלקה 1
    • מחלקה 2
      • הגדרת שדות ושיטות למחלקה 2
    • מחלקה 3: מפעילה את מחלקה 2
    • ממשק 4
      • הגדרת שיטות לממשק 4
      • מחלקה 4א : מממשת ממשק 4
  • (וכולי)
  • מחלקת Program
    • פונקציה ראשית Main
      • אובייקט _1א מממש את מחלקה 1א
      • אובייקט _1א. הפעלת שיטה X
      • אובייקט _3 מממש את מחלקה 3
      • אובייקט _3.הפעלת שיטה Y
      • אובייקט _4 מממש את מחלקה 4
      • אובייקט _4.הפעלת שיטה Z
      • המתנה לבקשת סיום מהמשתמש

ראו גם

עריכה

קישורים חיצוניים

עריכה
  מדיה וקבצים בנושא תכנות מונחה-עצמים בוויקישיתוף

הערות שוליים

עריכה
  1. ^ ע"פ Benjamin C. Pierce, Types and Programming Languages עמ' 226–227, וע"פ על כוס קפה, מדריך לשפת C# עמ' 15-16