
التجريد Abstract في Dart 19
تُعرَّف الكلاسات Abstract في Dart بأنها تلك الكلاسات التي تحتوي على abstract method واحد أو أكثر (method بدون تنفيذ) فيها. حيث أنه من أجل الإعلان عن كلاس مجرد Abstract class فإننا نستخدم الكلمة الأساسية abstract لذلك يجب ملاحظة أن الكلاسات المُعلن عنها “abstract” قد تتضمن أو لا تتضمن دوال مجردة abstract method ولكن إذا كانت تتضمن abstract method فيجب أن تكون abstract class.
ويُشير مصطلح “التجريد” (abstraction) إلى عملية إخفاء تفاصيل تنفيذ الكود وتقديم واجهة مبسطة ومستقلة عن التفاصيل الداخلية. ويُستخدم التجريد لتحقيق مستوى من الواجهة والتفاصيل المناسب لتحقيق هدف معين.
هناك عدة طرق لتحقيق التجريد في Dart. واحدة من هذه الطرق هي استخدام الكلاسات والإنترفيسات.
1 – الكلاسات (Classes): يمكنك استخدام الكلاسات في Dart لتحقيق التجريد. يمكنك إنشاء كلاس يحتوي على خصائص ووظائف معينة، ومن ثم استخدام كائنات من هذا الكلاس للتعامل مع تلك الوظائف. بتحديد واجهة عامة للكلاس واخفاء التفاصيل الداخلية، يمكنك تحقيق التجريد. على سبيل المثال:
abstract class Animal { void makeSound(); void eat() { print('Eating...'); } } class Dog extends Animal { void makeSound() { print('Bark!'); } } void main() { var dog = Dog(); dog.makeSound(); // يطبع "Bark!" dog.eat(); // يطبع "Eating..." }
في هذا المثال، الكلاس Animal هو كلاس تجريدي يحتوي على واجهة makeSound() و eat()، وبالتالي يمكن استخدامه لإنشاء كائنات من نوع Animal. الكلاس Dog يمتلك تنفيذًا محددًا لهاتين الوظيفتين، وبالتالي يمكن استخدام كائنات من نوع Dog لاستدعاء الوظائف المحددة.
2 – الإنترفيسات (Interfaces): يمكن استخدام الإنترفيسات في Dart لتحقيق التجريد. الإنترفيس هو عقدة تعريف واجهة تحتوي على توقيعات الوظائف فقط دون تنفيذها. يمكن للكلاسات تنفيذ الإنترفيسات وتقديم تنفيذ لوظائف الإنترفيس. على سبيل المثال:
abstract class Flyable { void fly(); } class Bird implements Flyable { void fly() { print('Flying...'); } } void main() { var bird = Bird(); bird.fly(); // يطبع "Flying..." }
في هذا المثال، الإنترفيس Flyable يحتوي على وظيفة fly()، ويمكن للكلاس Bird تنفيذ الإنترفيس Flyable وتقديم تنفيذ لوظيفة fly().
باستخدام الكلاسات والإنترفيسات في Dart، يمكنك تحقيق التجريد وإخفاء التفاصيل الداخلية لتحقيق واجهة مبسطة ومستقلة عن التفاصيل.
ميزات كلاس Abstract في Dart
- يجب الإعلان عن الكلاسات التي تحتوي على دوال مجردة abstract method بأنها مجردة بينما قد يكون للكلاس المُعلن عنه abstract method أو قد لا يكون أي أنه يمكن أن يكون له دوال مجردة أو ملموسة.
- يمكن الإعلان عن كلاسات مجردة بإستخدام الكلمة الأساسية المجردة abstract فقط.
- لا يمكن تهيئة كلاس تم إعلانها على أنها مجردة.
- يمكن تمديد كلاس مجردة و لكن إذا ورث كلاس مجرد فعليك التأكد من أن جميع الدوال المجردة فيها مزودة بالتنفيذ.
بشكل عام تُستخدم الكلاسات المجردة لتنفيذ الدوال المجردة في الكلاسات الفرعية الممتدة.
الشكل العام Syntax
abstract class class_name { // Body of the abstract class }
مثال
abstract class Data { void say(); void write(); } class Programmertech extends Data{ @override void say() { print("Yo Good!!"); } @override void write() { print("Programmer Tech"); } } main() { Programmertech tech = new Programmertech(); tech.say(); tech.write(); }
عند تشغيل الكود السابق ستكون النتيجة
Yo Good!! Programmer Tech
استخدام الكلاسات التجريدية في Dart لتحقيق واجهة مبسطة
في لغة Dart، لا يوجد مفهومٌ مباشر للكلاسات التجريدية (abstract classes) التي تستخدم لتحقيق واجهة مبسطة. ومع ذلك، يمكنك استخدام الكلاسات التجريدية في Dart لتحقيق التجريد وإخفاء التفاصيل الداخلية.
عند استخدام الكلاس التجريدي، يمكنك تعريف واجهة عامة تحدد الوظائف التي يجب تنفيذها في الكلاسات المشتقة. وبذلك، يمكنك استخدام الكائنات التي تنتمي إلى الكلاس التجريدي للتفاعل مع الواجهة المبسطة بدلاً من التعامل مع التفاصيل الداخلية لكل كلاس مشتق.
لنلقِ نظرة على مثال يوضح ذلك:
abstract class Animal { void makeSound(); } class Dog extends Animal { void makeSound() { print('Bark!'); } } class Cat extends Animal { void makeSound() { print('Meow!'); } } void main() { Animal dog = Dog(); Animal cat = Cat(); dog.makeSound(); // يطبع "Bark!" cat.makeSound(); // يطبع "Meow!" }
في هذا المثال، لدينا الكلاس التجريدي Animal والذي يحتوي على وظيفة makeSound()، ويتم تنفيذه في الكلاسات المشتقة Dog و Cat. يمكننا إنشاء كائنات من الكلاسات المشتقة وتعيينها إلى متغيرات من النوع Animal، وبذلك يمكننا استخدام الواجهة المبسطة المقدمة من الكلاس التجريدي للتفاعل مع الكائنات.
مع ذلك، يجب الانتباه إلى أنه في Dart، يمكن للكلاسات المشتقة من الكلاسات التجريدية تنفيذ وظائف إضافية وإضافة خصائص جديدة. وبالتالي، قد يكون هناك تفاصيل إضافية في الكلاسات المشتقة لا تنتمي إلى الواجهة المبسطة المقدمة من الكلاس التجريدي.
ما هي الفوائد الرئيسية لاستخدام الكلاسات التجريدية في Dart؟
استخدام الكلاسات التجريدية في Dart يوفر العديد من الفوائد الرئيسية، بما في ذلك:
- التجريد وإخفاء التفاصيل الداخلية: تسمح الكلاسات التجريدية بتجريد التفاصيل الداخلية وإخفائها عن المستخدمين الآخرين. يمكنك تعريف واجهة عامة للكلاس التجريدي تحدد الوظائف المتاحة للاستخدام الخارجي، بينما يتم إخفاء تفاصيل التنفيذ الداخلي. هذا يساهم في تبسيط استخدام الكود وتقليل التعقيد.
- التوحيد وإعادة استخدام الكود: باستخدام الكلاسات التجريدية، يمكنك تحديد مجموعة مشتركة من الوظائف والسلوكيات التي يجب تنفيذها في الكلاسات المشتقة. هذا يسمح بإعادة استخدام الكود بشكل فعال، حيث يمكنك إنشاء عدة كلاسات مشتقة تنفذ نفس الواجهة وتوفر سلوكًا مختلفًا. هذا يوفر وقت التطوير ويقلل من احتمالية وجود أخطاء متكررة.
- الإبقاء على التعقيد تحت السيطرة: باستخدام الكلاسات التجريدية، يمكنك تقسيم التعقيد الكبير إلى أجزاء أصغر ومُدارة بشكل منفصل. يمكنك تنفيذ التفاصيل الداخلية المعقدة في الكلاسات المشتقة بينما يتم تقديم واجهة بسيطة ومبسطة للتفاعل معها. هذا يسهل فهم الكود وصيانته واختباره.
- تسهيل التعاون والتطوير الموازي: باستخدام الكلاسات التجريدية، يمكن لفريق التطوير العمل بشكل مستقل على تنفيذ الكلاسات المشتقة دون الحاجة إلى معرفة التفاصيل الداخلية للكلاس التجريدي. يمكنهم التركيز على تنفيذ واجهة الكلاس التجريدي وضمان توافقها مع المتطلبات المحددة، مما يسهل التعاون ويزيد من إنتاجية الفريق.
باختصار، استخدام الكلاسات التجريدية في Dart يوفر تجريدًا وإعادة استخدامًا وتبسيطًا للكود، بالإضافة إلى تسهيل التعاون وإدارة التعقيد. هذه الفوائد تساعد على تحسين جودة البرمجيات وزيادة كفاءة عملية التطوير.
مثال الشخص والموظف والطالب
abstract class Person { String name; void introduceYourself(); } class Employee extends Person { String position; void introduceYourself() { print('Hello, my name is $name and I work as a $position.'); } } class Student extends Person { int grade; void introduceYourself() { print('Hi, I'm $name and I'm in grade $grade.'); } } void main() { Person employee = Employee(); employee.name = 'John'; employee.position = 'Manager'; employee.introduceYourself(); // يطبع "Hello, my name is John and I work as a Manager." Person student = Student(); student.name = 'Alice'; student.grade = 10; student.introduceYourself(); // يطبع "Hi, I'm Alice and I'm in grade 10." }
في هذا المثال، لدينا الكلاس التجريدي Person الذي يحتوي على خاصية name ووظيفة introduceYourself() التي يجب تنفيذها في الكلاسات المشتقة. تم تنفيذ الوظائف المطلوبة في الكلاسات المشتقة Employee وStudent. يمكننا استخدام الكلاسات المشتقة لإنشاء كائنات والتعامل معها باستخدام الواجهة المبسطة التي توفرها الكلاس التجريدي.
مثال الشكل الهندسي والمستطيل والمثلث
abstract class Shape { double getArea(); double getPerimeter(); } class Rectangle extends Shape { double width; double height; double getArea() { return width * height; } double getPerimeter() { return 2 * (width + height); } } class Triangle extends Shape { double base; double height; double getArea() { return 0.5 * base * height; } double getPerimeter() { return base + 2 * height; } } void main() { Shape rectangle = Rectangle(); rectangle.width = 5; rectangle.height = 3; print('Rectangle Area: ${rectangle.getArea()}'); // يطبع "Rectangle Area: 15.0" print('Rectangle Perimeter: ${rectangle.getPerimeter()}'); // يطبع "Rectangle Perimeter: 16.0" Shape triangle = Triangle(); triangle.base = 4; triangle.height = 6; print('Triangle Area: ${triangle.getArea()}'); // يطبع "Triangle Area: 12.0" print('Triangle Perimeter: ${triangle.getPerimeter()}'); // يطبع "Triangle Perimeter: 16.0" }
في هذا المثال، لدينا الكلاس التجريدي Shape الذي يحتوي على وظائف getArea() وgetPerimeter() التي يجب تنفيذها في الكلاسات المشتقة. تم تنفيذ الوظائف المطلوبة في الكلاسات المشتقة Rectangle وTriangle. يمكننا استخدام الكلاسات المشتقة لحساب مساحة ومحيط الأشكال الهندسية بسهولة.
هذه أمثلة بسيطة توضح استخدام الكلاسات التجريدية في Dart لتحقيق التجريد وإخفاء التفاصيل الداخلية وتوفير واجهة بسيطة للتفاعل مع الكائنات. يمكنك استخدام هذا المفهوفي الأمثلة السابقة، تم استخدام الكلاسات التجريدية لتعريف واجهة عامة تحدد الوظائف التي يجب تنفيذها في الكلاسات المشتقة. هذا يسمح بتبسيط الاستخدام وإمكانية إعادة استخدام الكود. كما يتم تحقيق التجريد وإخفاء التفاصيل الداخلية للكلاسات المشتقة، مما يسهل الصيانة والتعاون في عملية التطوير.
هل يمكنني استخدام الكلاسات التجريدية في Dart لتعريف واجهات أخرى؟
في لغة Dart، لا يمكن استخدام الكلاسات التجريدية (Abstract Classes) لتعريف واجهات (Interfaces). واجهات دارت تُعرف باستخدام الكلمة المفتاحية abstract ولا تحتوي على تنفيذات معينة للوظائف.
لتعريف واجهة في Dart، يمكنك استخدام الكلمة المفتاحية abstract وتعريف الوظائف دون توفير أي تنفيذات لها. هناك اختلاف بسيط في الصيغة بين تعريف الكلاسات التجريدية وتعريف الواجهات. هذا يعني أنه يجب على الكلاسات التي تريد تنفيذ الواجهة استخدام الكلمة المفتاحية implements بدلاً من extends التي تستخدم لتوريث الكلاسات التجريدية.
هنا مثال يوضح كيفية تعريف واجهة وتنفيذها في Dart:
abstract class Animal { void makeSound(); } class Cat implements Animal { void makeSound() { print('Meow!'); } } class Dog implements Animal { void makeSound() { print('Woof!'); } } void main() { Animal cat = Cat(); cat.makeSound(); // يطبع "Meow!" Animal dog = Dog(); dog.makeSound(); // يطبع "Woof!" }
في هذا المثال، لدينا الواجهة Animal التي تحتوي على وظيفة makeSound() بدون توفير أي تنفيذ لها. يتم تنفيذ الواجهة في الكلاسات Cat وDog باستخدام الكلمة المفتاحية implements وتوفير تنفيذ لوظيفة makeSound() في كلا الكلاسين. يمكننا استخدام الكائنات التي تنفذ الواجهة لاستدعاء الوظائف المحددة في تعريف الواجهة.
يجب ملاحظة أنه في Dart، يمكن للكلاس أن ينفذ أكثر من واجهة واحدة باستخدام فاصلة منقوطة لفصل الواجهات المختلفة. على سبيل المثال:
abstract class InterfaceA { void methodA(); } abstract class InterfaceB { void methodB(); } class MyClass implements InterfaceA, InterfaceB { void methodA() { // تنفيذ methodA } void methodB() { // تنفيذ methodB } }
في هذا المثال، ينفذ MyClass كلاً من InterfaceA و InterfaceB ويقوم بتنفيذ وظائفهما المحددة.
لذلك، عندما تحتاج إلى تعريف واجهة في Dart، يجب استخدام الكلمة المفتاحية abstract وتعريف الوظائف المطلوبة دون تنفيذات. ثم يمكنك تنفيذ الواجهة في الكلاسات المرادة باستخدام الكلمة المفتاحية implements وتوفير تنفيذ لوظائف الواجهة في تلك الكلاسات.