من فوائد البرمجة الكائنية: الكبسلة Encapsulation

السلام عليكم ورحمة الله

منذ فترة كنت أود التكلم عن البرمجة الكائنية المنحى Object oriented programming، لكن ما أخرني هو أني لا أريد أن أتكلم عنها بطريقة أكاديمية بحتة، بل بطريقة تعكس الخبرة العملية التي مررنا بها وفي نفس الوقت تكون بأمثلة بسيطة يمكن أن ترسخ للمتلقي. والطريقة التي وجدتها هي أن أتكلم عن فائدة واحدة في كل تدوينة إن شاء الله، بحيث يكون التركيز على هذه الفائدة فقط حتى يتم الفهم بإذن الله.

البرمجة الكائنية هي طريقة جديدة لتصميم وكتابة البرامج جاءت بعد البرمجة الهيكلية، وفكرتها تكمن في أن نقوم بتحويل أجزاء البرامج المختلفة إلى كائنات أو كينونات صغيرة تمثل هدف أو كائن ما.

مثلاً في برنامج لمحرك بحث يمكن أن يكون هناك كائن اسمه Site تكون بياناته عنوان موقع في النت ومسؤليته هي قراءة محتويات هذا الموقع وفهرسته في قاعدة بيانات محلية. فنلاحظ وجود عنصر البيانات، وهو عنوان الموقع، ويوجد أيضاً إجراء، مثل تحميل محتويات الموقع، ثم إضافتها في قاعدة بيانات. في البرمجة الهيكلية لا يوجد ربط بين البيانات واﻹجراءات، فمثلاً لحل نفس هذه المشكلة بطريقة هيكلية، يتم عمل إجراء أو دالة مثلاً ReadSite بالشكل التالي:

function ReadSite(aURL: string): string;

ويمكن إرسال أي موقع لهذه الدالة لتقوم بقراءة محتوياته ثم إرجاعها للمنادي. وبالنسبة للبيانات المدخلة (المتغير aURL) لا يتم اﻹحتفاظ به بعد نهاية نداء الدالة، وتصبح ليس لديه قيمة.

وعندما نُريد إدخال بيانات الموقع في قاعدة بيانات نقوم بعمل دالة أو إجراء آخر لتخزينها في قاعدة البيانات

function StoreSite(aURL: string; aContent: string): Boolean;

ولا يكون هناك ربط مباشر بين اﻹجرائين، إنما على المنادي لهما التأكد من إرسال البيانات الصحيحة في كل مرة.

إذا كان البرنامج بسيط ربما لاتكون هناك مشكلة، لكن عندما يصبح البرنامج معقد وفيه أن يحاول قراءة الصفحات التي تعذر الوصول لها في أول مرة، وأن يقوم البرنامج بقراءة عدد من الصفحات في نفس الوقت، نجد أن البرمجة الهيكلية لاتصلح لهذا التعقيد، لأنها تتعامل بفصل البيانات عن اﻹجراءات ونداء اﻹجراءات والدوال بطريقة stateless، أي لا يهم قيمة المتغيرات بعد الفراغ منها.

عندما ننظر لنفس البرنامج بطريقة كائنية، نجد أنه يمكن عمل كائن إسمه Site به بيانات وإجراءات مرتبطة ببعضها. في لغة أوبجكت باسكال نقوم بتعريفه بالطريقة التالية:


type
  TSite = class
  private
    fURL: string;
    fContents: string;
  public
    constructor Create(aURL: string);
    procedure ReadSite;
    procedure StoreSite;
end;

constructor TSite.Create(aURL: string);
begin
  // Initialize object data
  fURL:= aURL;
end;

procedure TSite.ReadSite;
begin
  // Read site from Internet using fURL
end;

procedure TSite.StoreSite;
begin
  // check if fContents is empty then call ReadSite
  // Store fContents in database
end;

وباستخدام لغة جافا:

public class Site {
  private String url = null;
  private String content = null;

  public void Site(String aURL){

  // Initialize object data
  url = aURL;
 }

public void readSite() {
  // put your reading code here
  // put result in content variable
}

public void storeSite() {
  // check if content = null then call readSite
  // store content in database
}

}

نجد في المثالين السابقين أننا أولاً عرفنا متغير fUrl في لغة باسكال أو url في لغة جافا وذلك لوضع عنوان الموقع طلية استخدام هذا الكائن، وتم التعريف لهذا المتغير داخل جسم الكائن، كذلك فإن تعريف اﻹجراءات الخاصة به تم تعريفها داخله أيضاً. بذلك نكون قد حققنا هذه المعادلة:

كائن = بيانات + إجراءات

وبهذا حققنا أحد مفاهيم الكبسلة، وهي أن تضع البيانات والكود في كبسولة واحدة يمكن التحرك بها كتلة واحدة، مثلاً يمكن أن تقوم بإرسال كائن (كمتغير) كاملاً إلى إجراء.

فبهذه الطريقة نكون قد حللنا مشكلة فهرسة عدد من المواقع في نفس الوقت، حيث يمكن نداء 10 نُسخ مختلفة instances من هذا الكائن، كل نسخة تحمل موقع مختلف عن النسخة اﻷخرى ولا يحدث تداخل في العناوين.

نلاحظ أنه في المثال قمنا بإتاحة إدخال العنوان فقط أثناء تهيئة نسخة جديدة (متغير جديد) قبل اﻹستخدام، ويكون بالطريقة التالية في لغة أوبجكت باسكال:


var
  Site1: TSite;
begin
  Site1:= TSite.Create('http://code.sd');
  Site1.ReadSite;
  Site1.StoreSite;

وفي لغة جافا:

  Site site1 = new Site("http://code.sd");
  site1.readSite();
  site1.storeSite();

وعند نداء اﻹجلاء readSite يتم إستخدام المتغير الداخلي المربوط بالكائن fUrl/url ولا يمكن الوصول إليه بالقراءة أو التغيير، لذلك وضعنا هذا المتغير في قسم private وهو يعني عدم إمكانية الوصول له خارج الكائن، فقط تستخدمه إجراءات الكائن.
بهذه الطريقة لا يمكن تغيير العنوان بين نداء اﻹجراء readSite و sotreSite كذلك لا يمكن تغيير المحتويات. أما في حالة البرمجة الهيكلية فيمكن أن يغلط المبرمج في نداء اﻹجراء التالي:

 function StoreSite(aURL: string; aContent: string): Boolean;

بحيث يعطي عنوان ومحتويات غير متعلقة ببعضها، وتنتج عنه معلومات غير متناسقة inconsistent

وبهذا نكون قد حققنا المفهوم أو الهدف الثاني للكبسلة وهو إخفاء البيانات information hiding وهي تقضي بأن البيانات المهمة يجب حجبها من المستخدم (المبرمج) إلا عن طريق مداخل محددة لا ينتج عنها تخريب للبيانات. وفي مثالنا المدخل الوحيد هو عند تهيئة الكائن.

كذلك فإنه بطريقة البرمجة الكائنية يمكن حل مشكلة أن بعض المواقع يتعذر الوصول إليها لفهرستها في بعض اﻷحيان، فيمكن بوضع متغير جديد لمتابعة أن عملية القراءة تمت أم تعذرت، ويمكن أيضاً إضافة تاريخ لآخر محاولة لقراءة الموقع، فإذا تعذرت اﻵن، يمكن أن نعيد فهرسة الموقع بعد ساعة أو يوم مثلاً.

يمكن عمل إضافة لقراءة البيانات دون تغييرها بواسطة البرمجة الكائنية، وذلك عن طريق الخصائص properties في لغة أوبجكت باسكال:

   property URL: string read fURL;
   property Content: string read FContent;

أو دوال لقراءة المتغيرات دون تغييرها في لغة جافا، حيث أن لغة جافا ليس فيها إمكانية عمل خصائص:

public String getURL(){
  return(url);
}

public String getContent(){
return(content);
}

ويمكن إرسال الكائن ككبسولة إلى أي إجراء خارجي آخر كأنه مدخل عادي مثال:


procedure CheckSite(aSite: TSite);
begin
  aSite.ReadSite;
  if Pos('error', aSite.Content ) = 1 then
    // Do something;
end;

كتلخيص للكبسلة هي تحقيق شيئين:

  1. جمع البيانات والإجراءات في كائن واحد نتعامل معهما كوحدة واحدة
  2. إخفاء المتغيرات التي لانرغب في أن يصل إليها المستخدم وإتاحة مداخل محددة لتغيير وقراءة البيانات والمعلومات

6 thoughts on “من فوائد البرمجة الكائنية: الكبسلة Encapsulation

  1. شرحٌ جميل ^_^

    سبقتَني إلي الكتابة عن هذا الموضوع؛ فعندي شرحٌ مختصرٌ للبرمجة الكائنية كنتُ قد كتبتُه أيام الكلية لزملائي، و ربما أنشره في الأيام التالية بإذن الله تعالي علي مدونتي.
    بالمناسبة: المثالان اللذان أوردتَهما لنفس كود الصنف Tsite مرة بالجافا و مرة بالأوبجكت باسكال قد يوضحان لك ما عنيتُه بأن الأوبجكت باسكال تتعنت أكثر من الجافا في هيكل البرنامج المكتوب بها، فقط انظر إلي:
    * عدد أسطر الصنف في الكودين.
    * مقروئية readability و مكتوبية writability الكودين.

  2. نعم صحيح، لاحظت ذلك أثناء الكتابة. فلغة جافا مصممة لأن تكون طبيعتها لغة كائنية فقط وليس فيها طريقة للبرمجة الهيكلية، لذلك فإن البرمجة الكائنية أبسط كما يظهر في المثال.
    لكن ننتظر حتى نتعمق أكثر في البرمج الكائنية والبرمجة المعتمدة على المكونات Component driven

  3. اعتقد أن الكبسلة من أهم ميزات البرمجة الكائنية بعد الوراثة فهي ضرورية لحماية الكائنات عبر تحديد دقيق لطريقة الوصول إلى الخصائص عبر ثﻻثة مستويات بابليك بروتاكتد برايفت و اهم انعكاساتها على البرمجة هي توفير نظام التأكد من المعطيات (data validation)

  4. نعم صحيح يُمكن إجراء تأكد من البيانات عند إدخالها، فبخلاف التعامل مع المتغيرات مباشرة والذي يُعطي سماحية إدخال قيم حتى لو كانت غير منطقية، مثلاً تاريخ الميلاد يكون لم يأت بعد يُمكن منعه عند استخدام الكبسلة.

  5. التوجه الكائني اسلوب جميل وبسيط وخلاق وابداعي يسهل على جميع الاطراف فهم ما يمكن فهمه من الكود البرمجي ويكفي ان لغة جافا تدعمه بنسبة 100% وهذا من دواعي السرور لكن اخواني نحتاج التمرس في هذه اللغات وفهمها حتى يتثني لنا مقارعة الكبار خاصه واصبح كل شي متاح
    موسى الزبير -سنار- السودان

أضف تعليقاً

إملأ الحقول أدناه بالمعلومات المناسبة أو إضغط على إحدى الأيقونات لتسجيل الدخول:

WordPress.com Logo

أنت تعلق بإستخدام حساب WordPress.com. تسجيل خروج   / تغيير )

صورة تويتر

أنت تعلق بإستخدام حساب Twitter. تسجيل خروج   / تغيير )

Facebook photo

أنت تعلق بإستخدام حساب Facebook. تسجيل خروج   / تغيير )

Google+ photo

أنت تعلق بإستخدام حساب Google+. تسجيل خروج   / تغيير )

Connecting to %s