תכנות מונחה עצמים
מתוך ויקיפדיה, האנציקלופדיה החופשית
בהנדסת תוכנה, תכנות מונחה עצמים (באנגלית: Object-oriented programming ובראשי תיבות OOP) הוא מתודולוגיה לפיתוח תוכנה, שהמימוש הבולט שלה הוא באמצעות שפות התכנות ++C ו־Java. כיום רוב שפות התכנות המודרניות תומכות בתפיסה זו, בצורה כזו או אחרת. בעוד שעד יצירת מתודולוגיה זו תהליך כתיבת התוכנה עבר אבולוציה התפתחותית, תכנות מונחה עצמים היווה מהפכה בכתיבת תוכנה, ודרש מהמתכנתים התייחסות אחרת לפתרון בעיות ורכישת הרגלי תכנות חדשים.
תוכן עניינים |
[עריכה] רקע
מתודולוגיה זו צמחה מהתכנות הפרוצדורלי והמודולרי שבוסס על שגרות ופונקציות שפעלו על מבני נתונים חופשיים. שיטה זו יצרה קושי רב, מכיוון שכל שינוי בהגדרת משתנים בתוכנית חייב שינוי בפונקציות שפעלו בכל מרחב התוכנה. ככל שהתוכנה הייתה גדולה ומורכבת הקושי הלך והתעצם, דבר שגרר תחזוקה רבה ואיטיות ומורכבות בפיתוח ככל שהתקדם, וכך, בניגוד למחירי החומרה שכל הזמן ירדו, מחירי התוכנות דוקא האמירו. לפיכך היה צורך לחפש מתודולוגיה חדשה שתפשט ותקל על עבודת התכנות.
אחד מהכיוונים לטיפול בבעיה היה ביסוס של פיתוח התוכנה על מודולות, כעין "קופסאות שחורות" שניתן להשתמש בהן שימוש משותף ולהעתיקן ליישומים נוספים, בבחינת שימוש חוזר (Reuse) של קוד, ובכך לקצר את תהליך פיתוח התוכנה (דבר שיושם למשל בקובצי DLL). בהסבר פשטני מאד, תכנות מונחה עצמים הוא תכנות שמבוסס על יצירת "קופסאות שחורות", שיש להם חיים עצמאיים משל עצמם, ואינם תלויים בגורם חיצוני. מהתפיסה הזו התפתחה מתודולוגיה שמחקה את העולם הממשי שקיימים בו עצמים ותתי עצמים, שלהם יש תכונות ופעולות משל עצמן. כך, כל תוכנה היא בעצם אוסף היררכי של אובייקטים רבים, שמתקשרים אחד עם השני לכדי מערכת גדולה ומתואמת.
יתרונה של מתודולוגיה זו היא שליטה בנפחים גדולים של קוד, על ידי חלוקה של עצמים לפי קטגוריות, דבר העוזר למיון וסידור המידע הרב, ועל ידי שיוך פעולות ומאפיינים לאובייקטים, כאשר מאפיינים בעלי משמעות לוגית דומה יכולים לפעול בצורה אחרת בהתאם לאובייקט שאליו הם מתייחסים. לדוגמה, התפיסה האנושית את העולם מחלקת אותו לקטגוריות של דומם, צומח, חי ואדם, וכל קטגוריה ראשית מתחלקת שוב לקטגוריות משנה, למשפחות ותתי משפחות. התכונות והפעולות, אף שיש להם משמעות דומה, יכולים לפעול בצורה אחרת בקטגוריות השונות. פעולת הנשימה, למשל, נעשית אחרת אצל דג ואצל אריה, אף שהינה דומה מבחינה לוגית: אצל הדג הפעולה מתבצעת על ידי קליטת חמצן מהמים באמצעות זימים, ואצל האריה על ידי קליטת החמצן מהאוויר באמצעות הריאות.
[עריכה] היסטוריה
הרעיון של עצמים ומופעים שלהם הופיע לראשונה בשנת 1963 בתוכנה בשם Sketchpad.
כמתודולוגיה לפיתוח תוכנה, מומש תכנות מונחה עצמים לראשונה בשפת הסימולציה Simula 67, שנוצרה בשנות השישים על־ידי הנורבגים אולה-יוהן דאל וקריסטן ניגארד. בשנת 2001 הוענק לשניים פרס טיורינג, בזכות תרומתם לפיתוחו של תכנות מונחה עצמים.
פיתוח ושכלול של הרעיון נעשו בשפת Smalltalk, שפותחה בשנות השבעים בזירוקס פארק. שפה זו זכתה להכרה נרחבת ולעניין רב באקדמיה.
בפיתוח תוכנה עסקית זכתה מתודולוגיה זו לתפוצה רחבה החל מאמצע שנות ה־80, תחילה בשפת התכנות ++C וטורבו פסקל, ולאחריה בשפת Java. שפות נוספות התומכות בתכנות מונחה עצמים הן פייתון, Ada (בגרסת 95), Ruby ,Delphi ועוד רבות אחרות.
במסגרת יוזמת NET. של חברת מיקרוסופט פיתחה החברה שפה חדשה לתכנות מונחה עצמים, #C, והשלימה יכולת זו שהייתה חלקית בגרסה ששית של שפת Visual Basic, בגרסה הקרויה Visual Basic .NET.
[עריכה] מאפייני תכנות מונחה עצמים
מרכיב בסיסי בתכנות מונחה עצמים הוא המחלקה (Class). מחלקה היא מבנה אבסטרקטי בעל תכונות (Properties) המגדירות ומאפיינות את המחלקה כלפי חוץ, ופעולות (Methods), שהן פונקציות יחודיות למחלקה. בחלק משפות התכנות קיימים גם אירועים (Events), שהם שגרות השייכות למחלקה ומוזנקות בהקשרים שונים, למשל בתחילתו או בסיומו של הליך או כתגובה לקלט מהמשתמש.
על מנת להשתמש במחלקה, המתכנת יוצר מופעים שלה. כל מופע של מחלקה הוא עצם (Object). היחס בין המחלקה לבין המופע, הוא היחס בין הגדרה של סוג לבין דוגמה ממשית מסוג זה. כלומר, בעוד שהמחלקה מהווה תבנית ומגדירה את התכונות והפעולות השייכות לה, המופעים הם אלה שמכילים את המידע הזה בפועל - כל עצם מכיל את התכונות והפעולות שהוגדרו במחלקה ממנה נוצר. לדוגמה, למחלקה הקרויה "מכונית" יש תכונות: צבע, דגם, שנת יצור, ופעולות: התנעה, נסיעה, עצירה. כל מכונית מסוימת היא עצם במחלקה זו, ולכל תכונה ערך המתאים למכונית המסוימת, למשל מזדה לבנה מודל 2003.
בכל מחלקה קיימות שתי פונקציות שמופעלות באופן אוטומטי על המופעים שלה בעת הופעתם ובעת מחיקתם. בעת יצירת המופע תופעל פונקציית בנאי (Constructor), באמצעותה אפשר לאתחל את האובייקט, לעתים באמצעות פרמטרים המועברים אליה. בעת הריסת האובייקט תופעל פונקציה הורסת (Destructor), באמצעותה אפשר למשל לשחרר זיכרון שהיה בשימוש על ידי העצם, או להרוס אובייקטים אחרים שכבר אין בהם צורך.
התכנות במתודולוגיה זו מצריך תכנון ומאמץ יתר מבשיטה הרגילה, מפני שצריך לנתח ולהגדיר את המערכת כולה מראש ולבנות את כל המודל שלה, שבו יוגדרו כל האובייקטים השונים וההיררכיה שביניהם. מצד שני למתכנת המשתמש באובייקטים, הרבה יותר קל להתמצא ולפתח כאשר הוא מתבסס על קוד של תכנות מונחה עצמים, מאשר על קוד פרוצדורלי.
[עריכה] עקרונות תכנות מונחה עצמים
לתכנות מונחה עצמים שלשה מאפיינים עיקריים: כימוס, הורשה ורב-צורתיות.
[עריכה] כימוס (Encapsulation)
יצירת האובייקט כמודול סגור וכ"קופסה שחורה", בה כל המכניזם הפנימי עלום וכמוס מפני המשתמש. התקשורת עם העצם מתבצעת רק דרך שיטות ומאפיינים כלליים הנכללים בו, דבר המאפשר בקרה טובה על כל הפעילות עם האובייקט. כל הנתונים הפנימיים כמו גם שיטות פנימיות, המשמשים את העצם, אינם ידועים מחוץ לעצם, ולכן ניתן לשנותם בחופשיות מבלי שיהיה צורך לשנות את התוכנות אשר משתמשות באובייקט. קשר מסוג זה בין עצמים קרוי תלות חלשה (loosely coupling), והוא מבטיח יצירת תוכנית מודולרית, פשוטה להבנה וניווט, וקלה לתחזוקה.
[עריכה] הורשה (Inheritance)
ניתן להגדיר מחלקה חדשה על בסיס מחלקה קיימת. למחלקה החדשה ישנן כל התכונות והפעולות שירשה מהמחלקה שעל-פיה הוגדרה, ובנוסף ניתן להגדיר פעולות נוספות במחלקה החדשה, או לשנות פעולות שירשה. המחלקה המורישה קרויה מחלקת בסיס (base class) או מחלקת אב (parent). המחלקה היורשת קרויה מחלקה נגזרת (derived class) או בן (child).
דוגמה: על בסיס המחלקה "רכב" שהוא רכב שנע על גלגלים בעזרת מנוע, אפשר להגדיר את המחלקות "אופנוע", "משאית", ו"מכונית", כאשר בכל אחת מהן יהיה שינוי בצורת הרכב, במנוע, ובגלגלים, ועל בסיס המחלקה "מכונית" ניתן להגדיר מחלקה חדשה "מונית", ובה תכונות ופעולות נוספות: כמו "כובע" המונית, הפעלת והפסקת מונה.
הדוגמה המובהקת ביותר לרעיון ההורשה מופיעה במיון עולם הטבע. בשיטת המיון ההירארכי הנהוגה בתחום זה, מוגדרות מחלקות ברמות אחדות. בכל אחת מהרמות נקבעות תכונות מסוימות, וכל רמה יורשת את התכונות של הרמות שמעליה. כאשר אנו פוגשים עצם מסוים בעולם החי, למשל כלבה ששמה "לאסי", אנו לומדים על תכונותיו על-פי המחלקה שאליה הוא משתייך.
ישנן שפות שבהן ניתן לרשת בו זמנית מכמה מחלקות בסיס, וליצור מחלקה שממזגת את התכונות של כמה מחלקות, ויש שפות המוגבלות לירושה ממחלקת בסיס אחת.
[עריכה] רב-צורתיות (Polymorphism)
היכולת לתת משמעויות שונות לפעולה בהקשרים שונים, וכך להתייחס לקבוצה של עצמים שונים באופן אחיד. המשמעות של פעולה נקבעת בהקשר של כל אחת מהמחלקות שבהן מוגדרת פעולה זו, ובהתאם לעצם שבו עוסקת הפעולה. רב-צורתיות עשויה להתממש בצורה דינמית בזמן העיבוד (תכונה הקרויה late binding) או בצורה סטטית בזמן ההידור.
החשיבות הגדולה של מנגנון הפולימורפיזם היא האפשרות להפשטה (abstraction) בתוכנה. המנגנון מאפשר כתיבת קוד כללי, מופשט, קוד הכתוב במונחי טיפוסים מופשטים ופועל כל פעם בהתאם לטיפוס הספציפי עליו הוא עובד.
מושגים הרווחים ברב צורתיות, הם:
- העמסת פרמטרים, שבו ניתן ליצור כמה פונקציות בעלות שם זהה אך בעלות פרמטרים שונים. דבר זה שימושי לריכוז כל הפונקציות תחת אותה קורת גג, במקום לכתוב פונקציות רבות בעלות שם שונה שמבצעות למעשה את אותה פעולה מבחינה לוגית.
- העמסת אופרטורים, שבו אופרטור מסוים שומר על צורתו הלוגית אך מקבל מכניזם פנימי שונה בתוך אובייקט. למשל אופרטור + שנועד לחבר מספרים, במחלקה של מחרוזות מקבל יכולת שרשור, ובמחלקה של מערכים יכול לקבל יכולת לחבר בין שני מערכים.
- דריסה (Override) שבה ניתן להחליף פונקציה של מחלקת בסיס בפונקציה שונה במחלקה הנגזרת ממנה. טכניקה נוספת היא הצללה שדומה ליכולת הדריסה.
דוגמה: אם נצמד לדוגמה הקודמת של כלי רכב, כאשר יורשים את מחלקת רכב, למשאית ולמכונית בשתיהן מדובר על מנוע, אבל המנוע יהיה אחר ואף שפעולותיו יהיו בשמות דומים הוא עשוי לבצע פעולות אחרות.
דוגמה נוספת: פעולת החיבור מוגדרת במחלקת המספרים הטבעיים, במחלקת המספרים הממשיים, במחלקת המספרים המרוכבים וכו'. בכל המחלקות הפעולה קרויה "חיבור", וניתן להשתמש בה באופן אחיד בקבוצת מספרים, בלי תלות במחלקה אליה משתייכים מספרים אלה.
[עריכה] ביקורת
למרות יתרונותיה של השיטה ככלי עזר למתכנתים, היא סובלת מחסרונות רבים הבאים לידי ביטוי בתוצר הסופי - התוכנה המוגמרת.
ההפשטה של ייעוד התוכנה לכדי עצמים מוגדרים שקל יותר להתעסק איתם, יוצרת פער בין מה שהמתכנת רואה לבין מה שהמחשב מבצע בפועל. הפער הזה מושלם על ידי המהדר, שמעצם היותו כלי אוטומטי עושה בדרך כלל עבודה גרועה יחסית. התוצאה היא "ניפוח" התוכנה הסופית, האטת זמן הריצה וניצול לא יעיל של משאבי זיכרון.
חוסר התלות בין העצמים גורמת פעמים רבות לכפילויות, הן בהגדרות המשתנים והן בפעולות המבוצעות על ידי התוכנה. כך, למשל, משתנה מסוים או פונקצייה מסוימת יכולים להתקיים בנפרד תחת הרבה אובייקטים שונים, למרות שדרוש רק מופע אחד שלהם. כמו כן, אותה פעולה בדיוק עשויה להיות מבוצעת פעמיים ויותר, כל פעם תחת אובייקט אחר (למשל, בדיקה של תקינות הקלט). שני אלה גורמים, שוב, לניפוח התוכנה וניצול לא יעיל של משאבי זמן וזיכרון.
האפשרות לשימוש חוזר בעצמים שהוגדרו בעבר, הנחשבת על ידי רבים כיתרונו הגדול של תכנות מונחה עצמים, גורמת לכך שמאפיינים ופעולות רבות שמוגדרים תחת אובייקטים בתוכנה מסוימת לא ישמשו אותה כלל ויבזבזו זיכרון ללא מטרה. יתרה מכך, חברות תוכנה משתדלות לעתים קרובות לדחוס לאובייקטים שלהן מאפיינים ופעולות רבות, רק על מנת שיוכלו להשתמש באותו אובייקט שוב ושוב מבלי לחזור ולשנות אותו בכל פעם. כתוצאה מכך נוצרים אובייקטים עמוסים לעייפה במאפיינים ופעולות חסרי שימוש, שתופסים שטח דיסק וזיכרון.
תכנות מונחה עצמים מאופיין בארגון מסיבי של הקוד, דבר המצריך זמן רב וגורם למתכנת לעסוק בסידור וארגון של הקוד במקום בבעיה בה התוכנה עוסקת. הדבר גורם לתוצר סופי שעיקר ההשקעה בו מופנית כלפי היכולת לתחזק את הקוד ולשנותו בעתיד, במקום באיכות הנוכחית שלו.
חסרונות אלה הולכים ומתעצמים ככל שרמת ההפשטה בתוכנה גבוהה יותר, וכך נוצר מצב בו האידאל של קוד מאורגן היטב, אליו שואפים המתכנתים, מביא לתוצאה הפוכה של תוכנה מסורבלת יותר, כבדה יותר ואיטית יותר.
[עריכה] ראו גם