ما هو التجريد (Abstraction) في البرمجة؟
في البرمجة، التجريد (abstraction) يعني إخفاء تفاصيل طريقة عمل شيء ما خلف واجهة أبسط، بحيث تستخدمه وأنت لا تعرف إلا ما يفعله. استدعاء sorted(names) يرتّب قائمة دون أن تكتب خوارزمية الترتيب أو حتى تراها.
آخر تحديث 24 سبتمبر 2026
حين تكتب print("hi") لا تفكر في كيفية وصول هذه الحروف إلى الشاشة. تحت هذا السطر الواحد، تحوّل بايثون النص إلى بايتات وتطلب من نظام التشغيل كتابتها، فيسلّمها نظام التشغيل إلى الطرفية، وترسم الطرفية كل حرف بالبكسلات باستخدام خط ما. كل طبقة تقدّم للطبقة التي فوقها وعدًا بسيطًا وتُخفي كيف تفي به. هذا الإخفاء هو التجريد، وكل برنامج يقف فوق طبقات كثيرة من هذا النوع.
مستويات التجريد
| المستوى | ما تتعامل معه | ما يُخفيه |
|---|---|---|
| برنامجك | print("hi") وsorted(names) | كيف تؤدي المكتبة العمل |
| بايثون ومكتبتها القياسية | النصوص والقوائم والملفات | إدارة الذاكرة واستدعاءات النظام |
| المفسر (CPython) | الـ bytecode | كود C وكود الآلة اللذان يشغّلانه |
| نظام التشغيل | الملفات والعمليات | كتل القرص وتعريفات الأجهزة وجدولة المعالج |
| العتاد | تعليمات الآلة | الترانزستورات والإشارات الكهربائية |
كل مستوى مبني من المستوى الذي تحته، ويمكن فهمه دونه. تستطيع كتابة كود بايثون يعمل دون أن تعرف ما هي كتلة القرص، ويستطيع نظام التشغيل تخزين ملف دون أن يعرف أنه يحمل كود بايثون.
كيف يعمل التجريد في الكود
يبني المبرمجون طبقاتهم الخاصة بطريقتين رئيسيتين.
التجريد الإجرائي هو الدالة. اسمها ومعاملاتها وقيمتها المُرجعة هي الواجهة، وجسمها هو التفصيل المخفي. بمجرد أن توجد average(scores)، يستخدمها باقي البرنامج دون أن يقرأ كيف تجمع وتقسم.
تجريد البيانات يعرّف النوع بما يمكنك فعله به، لا بطريقة تخزينه للأشياء. الطابور (queue) هو "أضف في الخلف، وخذ من الأمام". أما كيف تجلس العناصر في الذاكرة فقرار خاص:
serving soup
serving pasta
serving cake
الكود في الأسفل لا يعرف شيئًا عن deque. إن استبدلتها بقائمة عادية مع pop(0)، تبقى المخرجات مطابقة، لكنها أبطأ مع الطوابير الطويلة، لأن حذف أول عنصر من القائمة يحرّك كل العناصر الأخرى. بقيت الواجهة كما هي، فلم يلزم تغيير أي شيء خارج الصنف.
الأصناف المجردة والواجهات
في البرمجة كائنية التوجه، يعني التجريد عادةً تحديد ما يجب أن تفعله عائلة من الأصناف، وترك كيف لكل صنف. في بايثون تحدد الوحدة abc دالةً على أنها مجردة، والصنف الذي فيه دالة مجردة غير مطبقة لا يمكن إنشاء كائن منه:
email to ana@example.com: Your package arrives today
sms to +15550100: Your package arrives today
Notifier is abstract: create an Email or an SMS instead
لا تعتمد remind() إلا على التجريد: أي شيء له دالة send. وإضافة الإشعارات الفورية تعني كتابة صنف جديد واحد، وتبقى remind() دون تغيير. وتلك الخطوة الأخيرة، أي استدعاء واحد يُنفّذ كودًا مختلفًا لأصناف مختلفة، هي تعدد الأشكال: التجريد يحدد الواجهة المشتركة، وتعدد الأشكال يجعلها تعمل.
في جافا الأدوات نفسها على شكل كلمات محجوزة:
interface Notifier {
void send(String to, String text);
}
class Email implements Notifier {
public void send(String to, String text) { /* talk to the mail server */ }
}
كتابة new Notifier() خطأ ترجمة، لأن الواجهة ليس لها تطبيق يُنفَّذ. ويشرح التوثيق الأصناف المجردة والواجهات في جافا بالتفصيل.
الفرق بين التجريد والتغليف
تظهر الفكرتان معًا كثيرًا حتى يسهل الخلط بينهما.
| التجريد | التغليف | |
|---|---|---|
| السؤال الذي يجيب عنه | ماذا يفعل هذا؟ | من يحق له لمس البيانات؟ |
| محور التركيز | الواجهة: العمليات المعروضة | الداخل: البيانات التي خلف الواجهة |
| الأدوات الرئيسية | الدوال، والأصناف المجردة، والواجهات، والوحدات | private و_name والخصائص و#fields |
| مثال | Notifier.send() تعمل للبريد الإلكتروني والرسائل القصيرة | _balance لا يتغيّر إلا عبر withdraw() |
| المستوى | التصميم | التطبيق |
يقرر التجريد أي العمليات تُعرض، ويضمن التغليف أن يبقى الباقي مخفيًا. والصنف Queue أعلاه يفعل الأمرين: add وnext هما التجريد، والشرطة السفلية في _items هي التغليف.
التجريدات المُسرِّبة وأخطاء أخرى
صاغ Joel Spolsky عام 2002 ما سمّاه قانون التجريدات المُسرِّبة (law of leaky abstractions): كل تجريد غير بسيط يسمح لبعض التفاصيل المخفية بالتسرب. والأعداد العشرية (floating point) هي التسرب الكلاسيكي. تبدو أعدادًا عشرية عادية، حتى يظهر التخزين الثنائي الذي تحتها:
0.30000000000000004
False
لا يمكن تخزين 0.1 ولا 0.2 بدقة في بتات ثنائية، فيكون المجموع منحرفًا قليلًا. يمكنك استخدام الأعداد العشرية سنوات دون أن تفكر في هذا، لكن ليس إلى الأبد، ولهذا يفيدك أن تعرف طبقة واحدة تحت الطبقة التي تعمل فيها.
وهناك خطآن شائعان آخران:
- التجريد المبكر جدًا. هرم أصناف مبني لحالات لا تأتي أبدًا هو كود إضافي يُقرأ ويُغيَّر. وقد عبّرت Sandi Metz عن ذلك بقولها "التكرار أرخص بكثير من التجريد الخاطئ".
- الخلط بين التجريد والكلمة المحجوزة
abstract. الأصناف المجردة أداة واحدة. وكل دالة ذات اسم جيد هي تجريد أيضًا.
إلى أين بعد ذلك
اقرأ صفحتي التغليف وتعدد الأشكال لتكتمل صورة البرمجة كائنية التوجه. وتُظهر صفحة نظام التشغيل أكبر تجريد تعتمد عليه برامجك. وللتدرب، تبني دورة بايثون الأصناف والدوال من البداية، وتغطي دورة جافا الأصناف المجردة والواجهات.
الأسئلة الشائعة
ما هو مثال على التجريد؟
len(items) وأنت تعرف ما تُرجعه، لا كيف تعدّ بايثون. ودواسات السيارة هي النسخة اليومية، فأنت تتحكم في السرعة دون أن تعرف كيف يحرق المحرك الوقود. وفي الكود كائني التوجه، واجهة مثل Notifier لها دالة send واحدة هي تجريد فوق البريد الإلكتروني والرسائل القصيرة والإشعارات الفورية.ما هو التجريد في بايثون؟
abc التي تتيح لك التصريح عن صنف أساسي مجرد باستخدام @abstractmethod، وعندها ترفض بايثون إنشاء كائنات من ذلك الصنف، أو من أي صنف فرعي لم يطبّق كل الدوال المجردة.ما هو التجريد في البرمجة بلغة جافا؟
new. أما الواجهة فتسرد دوالًا يجب أن يوفرها كل صنف يطبقها، ويمكن للصنف أن يطبق عدة واجهات.