NET/מחלקות - היכרות

מתוך ויקיספר, אוסף הספרים והמדריכים החופשי
< NET
תכנות בסביבת NET








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

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

יסודות תכנות מונחה עצמים[עריכה]

הגדרת מחלקה[עריכה]

המחלקה מוגדרת באופן הבא:

C#:

[ [modifier] [modifier] ...] class ClassName {

// variables
// properties
// methods
// events

}

modifier יכול להיות אחד מהבאים:

  • public - המחלקה נגישה לכל המחלקות האחרות
  • internal - המחלקה נגישה רק למחלקות באותו Assembly (אותו קובץ exe או dll בו מוגדרת המחלקה)
  • private - רלוונטי רק למחלקות המוגדרות בתוך מחלקות אחרות. במקרה זה, המחלקה תהיה נגישה רק בתוך המחלקה בה הוגדרה.
  • static - מחלקה סטאטית. מחלקה כזו יכולה להכיל רק שדות בעלי המגדיר static בעצמם, ולא ניתן ליצור עצמים שלה. הגישה אל שדות במחלקה כזאת נעשית דרך שם המחלקה.
  • partial - מציין שהמחלקה מפוצלת לשני קבצים. מגדיר זה מאפשר לשים קוד "מנהלתי", שלא כולל לוגיקה אלא הגדרת משתנים למשל, בקובץ נפרד, ובכך להקל על הקריאה. עם זאת, אין הגבלה אמיתית על סוג הקוד שניתן לשים בכל חלק של המחלקה.

ברור שניתן לציין רק אחד מתוך public/internal/private בכל מחלקה, משום שהם סותרים זה את זה.

ClassName הוא שם המחלקה. השם יכול להכיל אותיות, מספרים וקו תחתי ('_'), אך לא יתחיל במספר. מקובל להשתמש בשמות בסגנון פסקל - כל מילה בשם מתחילה באות גדולה, ללא הפרדה בין המילים.

בנאים[עריכה]

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

מאפיינים[עריכה]

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

C#:

[[modifier] [modifier] [modifier]] return_type ProperyName {

  [modifier] get {
    statement
    return ...
  }
  [modifier] set {
    statement
  }

}

modifier הוא אחד ממגדירי רמת הגישה האפשריים עבור המאפיין, או המגדיר static. אם לא צויין modifier, ברירת המחדל היא private.

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

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

statement הוא סדרה של הוראות שיבוצעו כאשר תבוצע קריאה (get) או השמה (set) למאפיין.

חלק ה-get מבוצע כאשר נרצה לקבל את ערך המאפיין. חלק זה חייב להחזיר ערך במהלך ביצועו.

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

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

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

דוגמה:

C#:

private int _distance = 5;

public int Distance {
  get {
    return _distance;
  }
  protected set {
    _distance = value;
  }

}

VB.NET:

Private _distance As Integer = 5

Public Property Distance() As Integer
  Get
    Return
_distance
  End Get
  Protected Set

    _distance = value
  End Set

End Property

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

השמה למאפיין, לעומת זאת, מוגבלת למחלקה הנוכחית ולמחלקות יורשות (עוד על ירושה בהמשך), בעזרת רמת ההרשאה protected של חלק ה-set. הערך מתקבל במשתנה value, ומושם למשתנה _distance.

המילים get,‏ set ו־value הן בעלות משמעות רק בתוך ההקשר של מאפיין. מחוץ לתחומי המאפיין ניתן להשתמש בהן בחופשיות לשמות של משתנים, שגרות ומזהים אחרים.

בזמן תהליך ההידור, המהדר מתרגם כל מאפיין לשתי שגרות, עם הקידומות get_ ו־set_. לדוגמה, המאפיין שבדוגמה יתורגם למעשה לשתי שגרות:

C#:

public int get_Distance() {

  return _distance;
}
public void set_Distance(int value) {
  _distance = value;

}

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

מאפיינים אוטומטיים[עריכה]

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

C#:

public int Distance {

  get;
  set;

}

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

ב-VB.NET אין כיום כתיב מקביל דומה, אך ככל הנראה יתווסף עם שחרור הגרסה הבאה של ויז'ואל סטודיו[1] (גרסה 2010).

שגרות[עריכה]

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

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

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

המבנה של שגרה הוא כדלהלן:

C#:

[ [modifier] ...] return_type MethodName([parameters]) {

  // method logic

}

modifier - יכול להיות אחת מרמות ההרשאות private, protected, protected internal, internal, public. בנוסף, אפשר להוסיף את המילה השמורה static, שמשמעותה שאין צורך בעצם של המחלקה כדי לגשת אל השגרה, ויש לגשת אליה באמצעות שם המחלקה בלבד.

return_type - שם המחלקה של ערך ההחזרה, במידה והשגרה מחזירה ערך. אם השגרה אינה מחזירה ערך, נציין ערך החזרה void (שהוא למעשה כינוי למבנה System.Void), המציין שהשגרה אינה מחזירה ערך.

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

אירועים[עריכה]

סיכום ביניים[עריכה]

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

C#:

using System;

using System.Drawing;
public class Vehicle {
  private String _manufacturer;// manufacturer name
  private Color _color; // vehicle color

  /// <summary>
  /// 
Initialize a new instance of the <see cref="Vehicle"/> class
  /// </summary>
  /// <param name="manufacturer"/>The vehicle manufacturer</param>
  public Vehicle(String manufacturer) {
    _manufacturer = manufacturer;
  }

  /// <summary>
  /// 
Get or set the name of the vehicle manufacturer.
  /// </summary>
  public String Manufacturer {
    get {
      return _manufacturer;
    }
    set {
      _manufacturer = value;
    }
  }

  /// <summary>
  /// 
The vehicle color
  /// </summary>
  public Color Color {
    get {
      return _color;
    }
    set {
      _color = value;
    }
  }

}

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

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

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

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


ירושה[עריכה]

ב-NET. מחלקה יכולה לרשת ממחלקה אחרת או מממשק(interface) את כל(אפשר גם להגדיר שלא יוכלו לרשת משהו) הפונקציות,המשתנים, מאפיינים, אירועים, מצביעים(delgates).

  חלק זה של הספר הינו קצרמר. אתם מוזמנים לתרום לוויקיספר ולערוך אותו.