العودة للمدوّنة

فهم الكائنات وأنواع البيانات المجردة (ADTs) مع أمثلة

مقاربتان أساسيتان لتمثيل البيانات — أنواع البيانات المجردة (ADTs) للتغليف المبهم، والكائنات (Objects) للواجهات القابلة للتركيب — والمقايضات بينهما.

منشور أيضًا على
Understanding Objects and ADTs

في تطوير البرمجيات، توجد أساليب متعددة لتمثيل البيانات، لكلٍّ منها مزاياها ومقايضاتها. من أكثر الأساليب شيوعًا: أنواع البيانات المجردة (Abstract Data Types - ADTs) والكائنات (Objects). بينما تركّز الـ ADTs على تمثيل البيانات بشكل مبهم، تُركّز الكائنات على تمثيل البيانات عبر الواجهات القابلة للتركيب. دعنا نستكشف الفروق بين هذين الأسلوبين وتداعياتهما على تصميم البرمجيات.

أنواع البيانات المجردة (ADTs): تمثيل البيانات بشكل مبهم

توفّر الـ ADTs نموذجًا للبيانات يتكون من قيم وعمليات، مع إخفاء تفاصيل التنفيذ الداخلي عن المستخدمين. فمثلًا، قد يمتلك Set ADT عمليات مثل الإضافة والحذف والتحقق، دون الكشف عن كيفية تنفيذها داخليًا. بجوهرها، تُغلّف الـ ADTs البيانات والعمليات داخل مخطّط منطقي، مما يعزّز النمطية والتجريد.

Abstract Data Types (ADTs): Representing Data Opaquely

مثال بلغة C++

Set.cppC++
#include <vector>
#include <algorithm>

class Set {
  private:
    std::vector<int> elements;

  public:
    void add(int value) {
      if (!contains(value)) {
        elements.push_back(value);
        std::sort(elements.begin(), elements.end());
      }
    }

    bool contains(int value) const {
      return std::binary_search(elements.begin(), elements.end(), value);
    }

    bool isEmpty() const {
      return elements.empty();
    }
};

مثال بلغة Java

NumberSet.javaJava
import java.util.HashSet;
import java.util.Set;

public class NumberSet {
    private Set<Integer> set;

    public NumberSet() {
        set = new HashSet<>();
    }

    public void add(int value) {
        set.add(value);
    }

    public boolean contains(int value) {
        return set.contains(value);
    }

    public boolean isEmpty() {
        return set.isEmpty();
    }
}

الكائنات (Objects): تمثيل البيانات عبر الواجهات القابلة للتركيب

تُركّز الكائنات في تطوير البرمجيات على التغليف والبرمجة القائمة على الواجهات. خلافًا للبرمجة الشيئية (OOP) التقليدية القائمة على الأصناف والتي تتضمن في الغالب حالة قابلة للتغيير ووراثة، يتمحور تعريف الكائنات حول التغليف والالتزام بالواجهات.

Objects: Representing Data Through Composable Interfaces Press enter or click to view image in full size


مثال بلغة C++

Animal.cppC++
#include <iostream>
#include <string>

class Animal {
  public:
    virtual void speak() const = 0;
};

class Dog : public Animal {
  public:
    void speak() const override {
        std::cout << "Woof!" << std::endl;
    }
};

int main() {
    Dog dog;
    dog.speak();
    return 0;
}

مثال بلغة Java

Animal.javaJava
interface Animal {
    void speak();
}

class Dog implements Animal {
    public void speak() {
        System.out.println("Woof!");
    }
}

public class Main {
    public static void main(String[] args) {
        Dog dog = new Dog();
        dog.speak();
    }
}

المقايضات والاعتبارات

يوفّر كلٌّ من الـ ADTs والكائنات مزايا ومقايضات مختلفة. تتميّز الـ ADTs في توفير النمطية والتجريد، مما يجعلها سهلة التحسين والفهم. إلا أنها تفتقر إلى قابلية التوسيع، إذ لا يستطيع المستخدمون تعديل تمثيلاتها الداخلية مباشرةً. في المقابل، تتيح الكائنات المرونة وقابلية التوسيع، مما يُمكّن المستخدمين من إنشاء تمثيلات جديدة تتوافق مع الواجهات المحدّدة مسبقًا. وبينما تعزّز الكائنات البرمجة القائمة على الواجهات والتغليف، فقد تكون أقلّ كفاءةً من حيث الأداء مقارنةً بالـ ADTs.

الخلاصة

يُعدّ فهم الفروق بين الـ ADTs والكائنات أمرًا بالغ الأهمية لاختيار الأسلوب الملائم لمشكلة تصميم برمجي معيّنة. بينما تُولي الـ ADTs الأولوية للتغليف والتجريد، تُركّز الكائنات على البرمجة القائمة على الواجهات وقابلية التوسيع. ومن خلال الاستفادة من نقاط قوة كلٍّ من الأسلوبين، يستطيع المطوّرون تصميم أنظمة برمجية قوية وقابلة للصيانة. في المقالة القادمة، سنستعرض المقايضات والاعتبارات المتعلقة بتطبيق أنواع البيانات الجبرية (ADTs) ونقارنها بالمفاهيم التي ناقشناها هنا.

شكرًا لقراءتك! ❤️🥳

شكرًا لقراءتك! ❤️

يمكنك متابعتي عبر:
LinkedIn
Facebook
All My Social Media

My Portfolio:
https://www.omarwaleed.tech