כימוס

כּימוּס (או אֶנְקַפְּסוּלַצְיָה, מאנגלית: Encapsulation) הוא מאפיין חשוב בתכנות ובמיוחד בתכנות מונחה-עצמים המאפשר יצירת יחידת תוכנה בעלת ממשק מוגדר לשאר חלקי התוכנה. בשפות תכנות בעלות כימוס, אפשר להגדיר הרשאות גישה לאלמנטים שונים ביחידה. לדוגמה, ניתן להגדיר שפונקציה מסוימת ניתנת לגישה מכל מקום בקוד או רק מתוך הקוד של אותה יחידת תוכנה.
הכימוס באה לענות על בעיה של חוסר תיחום של קוד בתכנות פרוצדורלי, שבו משתנה אחד היה נגיש לכל מרחב הקוד, וכאשר נעשה בו שינוי או הוספו פונקציות שהתייחסו למשתנה שכבר קיים, הדבר גרם לכך שהקוד השתנה ללא בקרה, והשפיע על פונקציות אחרות ללא כל כוונה. הכימוס מסייע בבניית תוכנה בצורה מודולרית. מכיוון שליחידת התוכנה ממשק מוגדר, שאר הקוד אינו מסתמך על המימוש הפנימי שלה. הדבר מאפשר שינוי של המימוש הפנימי ללא שינוי של שאר התוכנה. יתרון נוסף של שימוש בכימוס הוא האפשרות להשתמש ביחידות תוכנה סגורות בלי צורך להבין את פרטי המימוש. יחידת התוכנה משמשת מעין "קופסה שחורה" או "קפסולה" עם מתגים. המשתמש צריך ללמוד רק איך להפעיל את המתגים ואינו צריך לדעת מה יש בתוך הקופסה.

דוגמה

הדוגמה הבאה מדגימה איך כימוס מאפשר שינוי מימוש פנימי ללא שינוי הקוד החיצוני. הקוד הבא ב-C++‎ מתאר מחסנית הממומשת באמצעות תור סטנדרטי:
#include <deque>class MyStack {private:
 std::deque<int> m_queue;public:
 void push(int x) {
 m_queue.push_front(x);
 }
 int pop() {
 int x = m_queue.front();
 m_queue.pop_front();
 return x;
 }};
ניתן לשנות את המימוש הפנימי לרשימה משורשרת:
#include <list>class MyStack {private:
 std::list<int> m_list;public:
 void push(int a) {
 m_list.push_front(a);
 }
 int pop() {
 int a = m_list.front();
 m_list.pop_front();
 return a;
 }};
כל קוד שמשתמש במחסנית יפעל באופן זהה על שתי הגרסאות שלה. לדוגמה:
#include <iostream>int main() {
 MyStack s;
 s.push(17); s.push(11);
 std::cout << s.pop() << std::endl;}
למרות שההתנהגות תהיה זהה בשתי הגרסאות, ייתכנו הבדלים בזמני הריצה.

דוגמאות מתחומים הנדסיים אחרים

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

כימוס והורשה

מטרת הכימוס היא להסתיר פרטי מימוש מקוד חיצוני. בהקשר זה, לא תמיד ברור אם קוד מחלקה יורשת נחשב פנימי או חיצוני. מצד אחד, ייתכן שקוד המחלקה היורשת נכתב על ידי מתכנת אחר שאינו בקיא בפרטי המימוש של מחלקת הבסיס. מצד שני, המשתנים של מחלקת הבסיס מהווים חלק מהמחלקה היורשת. שפות תכנות מסוימות, מאפשרות שליטה על רמת הכימוס ביחס למחלקה יורשת. ב-Java וב-C++‎ לדוגמה, ניתן להגדיר אלמנטים במחלקה כ-protected וכ-private. אף על פי ששתי הרשאות הגישה האלה, מסתירות את המימוש הפנימי מקוד חיצוני, רק הראשונה איננה מסתירה אותו ממחלקות יורשות.