"إذا أراد العامل أن يؤدي عمله بشكل جيد، فعليه أولاً أن يشحذ أدواته." - كونفوشيوس، "مختارات كونفوشيوس. لو لينجونج"
الصفحة الأمامية > برمجة > التكوين مقابل الميراث

التكوين مقابل الميراث

تم النشر بتاريخ 2024-11-09
تصفح:878

Composición vs Herencia

مقدمة

الوراثة والتركيب هما مفهومان أساسيان في البرمجة الشيئية (OOP)، لكن يتم استخدامهما بشكل مختلف ولهما أغراض مختلفة. الهدف من هذه التدوينة هو مراجعة تلك الأغراض، وبعض الأمور التي يجب مراعاتها عند اختيارها.

مفاهيم الميراث

عندما نفكر في تطبيق الوراثة في تصاميمنا، علينا أن نفهم:

  • تعريف: في الميراث، يمكن لفئة (تسمى فئة مشتقة أو فئة فرعية) أن ترث خصائص وسلوكيات من فئة أخرى (تسمى فئة أساسية أو فئة فائقة). يمكن للفئة المشتقة توسيع أو تعديل وظائف الفئة الأساسية.
  • العلاقة: هي علاقة "هي" (هي-أ). على سبيل المثال، إذا كان لديك فئة "مركبة" وفئة أخرى "سيارة"، فإن الفئة "سيارة" هي فئة فرعية من "مركبة".
  • المزايا: يعزز إعادة استخدام التعليمات البرمجية ويسمح بتوسيع الوظائف بسهولة.

مفاهيم التكوين

من ناحية أخرى، إذا فكرنا في تركيب الكائنات معًا:

  • تعريف: في التركيب، يحتوي الكائن على كائنات أخرى ويفوض جزءًا من وظائفه إليها. بدلاً من الوراثة، يستخدم الفصل مثيلات الفئات الأخرى لتحقيق وظائفه.
  • العلاقة: إنها علاقة "يملك". على سبيل المثال، إذا كان لديك فئة "محرك" وفئة "سيارة"، يمكن أن تحتوي الفئة "سيارة" على كائن من فئة "محرك".
  • المزايا: مرونة أكبر واقتران أقل بين الفئات. التغييرات في فئة واحدة لا تؤثر بشكل مباشر على الأخرى.

لماذا التأليف على الميراث؟

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

دعنا نستكشف مثالاً في Java يوضح كيف يمكن تفضيل التركيب على الميراث في حالات معينة. لنفترض أننا نعمل على نظام معالجة الطلبات في متجر إلكتروني.

  • منهج الميراث:

أولاً، دعونا نفكر في طريقة تستخدم الميراث لتمثيل أنواع مختلفة من المنتجات القابلة للشراء، مثل الكتب والإلكترونيات:

// Clase base para productos
class Producto {
    String nombre;
    double precio;

    Producto(String nombre, double precio) {
        this.nombre = nombre;
        this.precio = precio;
    }

    void procesarPedido() {
        System.out.println("Procesando pedido para "   nombre);
    }
}

// Clase para productos electrónicos que hereda de Producto
class ProductoElectronico extends Producto {
    String modelo;

    ProductoElectronico(String nombre, double precio, String modelo) {
        super(nombre, precio);
        this.modelo = modelo;
    }
}

// Clase para libros que hereda de Producto
class Libro extends Producto {
    String autor;

    Libro(String nombre, double precio, String autor) {
        super(nombre, precio);
        this.autor = autor;
    }
}

ينجح هذا الأسلوب، ولكن ماذا لو كنت بحاجة إلى تقديم أنواع منتجات جديدة أو إضافة وظائف محددة لأنواع معينة من المنتجات؟

  • التركيز مع التركيب:

بدلاً من الاعتماد كليًا على الميراث، يمكننا استخدام التركيب للتعامل مع أنواع مختلفة من المنتجات بشكل أكثر مرونة:

// Clase para productos
class Producto {
    String nombre;
    double precio;

    Producto(String nombre, double precio) {
        this.nombre = nombre;
        this.precio = precio;
    }

    void procesarPedido() {
        System.out.println("Procesando pedido para "   nombre);
    }
}

// Clase para productos electrónicos que utiliza composición
class ProductoElectronico {
    Producto producto;
    String modelo;

    ProductoElectronico(String nombre, double precio, String modelo) {
        this.producto = new Producto(nombre, precio);
        this.modelo = modelo;
    }

    // Puedes agregar lógica específica para productos electrónicos si es necesario
    void procesarPedidoEspecifico() {
        System.out.println("Procesando pedido específico para "   producto.nombre);
    }
}

// Clase para libros que utiliza composición
class Libro {
    Producto producto;
    String autor;

    Libro(String nombre, double precio, String autor) {
        this.producto = new Producto(nombre, precio);
        this.autor = autor;
    }

    // Puedes agregar lógica específica para libros si es necesario
    void procesarPedidoEspecifico() {
        System.out.println("Procesando pedido específico para "   producto.nombre);
    }
}

في هذا الأسلوب، يحتوي كل نوع منتج على مثيل لفئة المنتج، مما يسمح بمشاركة المنطق المشترك لمعالجة الطلبات. بالإضافة إلى ذلك، يمكن أن يكون لكل نوع منتج منطقه الخاص باستخدام طرق مثلprocessSpecificOrder(). هذا التصميم أكثر مرونة ويسهل تقديم أنواع منتجات جديدة أو تعديل المنطق الخاص بالنوع دون التأثير على التسلسل الهرمي للميراث.

متى يتم تطبيق الميراث؟

بينما يعتمد الاختيار بين الميراث والتركيب في تصميم البرمجيات على السياق والمتطلبات المحددة للمشكلة التي تعالجها. فيما يلي بعض المواقف التي قد تعتبر فيها الميراث خيارًا أكثر ملاءمة من التركيب:

  • علاقة "is-a": يكون الوراثة مناسبًا بشكل خاص عندما تكون هناك علاقة واضحة "is-a" بين الفئات. إذا كانت الفئة B عبارة عن نسخة أكثر تحديدًا أو تخصصًا من الفئة A، فإن الميراث يكون منطقيًا. على سبيل المثال، إذا كان لديك فئة مركبة وفئة سيارة، فإن العلاقة "is-a" تكون واضحة، نظرًا لأن السيارة هي نوع من المركبات.
class Vehiculo {
    // ...
}

class Automovil extends Vehiculo {
    // ...
}
  • إعادة استخدام الكود: يسمح الوراثة بإعادة استخدام الكود، حيث أن الفئة المشتقة ترث أعضاء الفئة الأساسية وأساليبها. يمكن أن يكون هذا مفيدًا عندما يكون هناك قدر كبير من التعليمات البرمجية المشتركة بين الفئات ذات الصلة.
class Animal {
    void comer() {
        // Lógica común para comer
    }
}

class Perro extends Animal {
    void ladrar() {
        // Lógica específica para ladrar
    }
}
  • تعدد الأشكال: الوراثة أمر أساسي لتنفيذ تعدد الأشكال، والذي يسمح للفئات المشتقة بتوفير تطبيقات محددة للطرق الموروثة من الفئة الأساسية. يعد هذا مفيدًا في السيناريوهات التي تحتاج فيها إلى التعامل مع كائنات الفئات المشتقة بشكل موحد.
class Figura {
    void dibujar() {
        // Lógica común para dibujar una figura
    }
}

class Circulo extends Figura {
    void dibujar() {
        // Lógica específica para dibujar un círculo
    }
}

class Cuadrado extends Figura {
    void dibujar() {
        // Lógica específica para dibujar un cuadrado
    }
}

  • ملحقات الوظائف: إذا كنت تقوم بتوسيع أو تخصيص الوظائف الحالية، فقد يكون الوراثة أكثر طبيعية. على سبيل المثال، إذا كنت تقوم بتطوير مكتبة وقمت بتوفير فئة أساسية ذات وظائف أساسية، فيمكن لمستخدمي مكتبتك الاشتقاق من تلك الفئة الأساسية لتوسيع هذه الوظيفة.

ماذا يحدث إذا تركنا ميراثًا سيئًا؟

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

خاتمة

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

بيان الافراج تم نشر هذه المقالة على: https://dev.to/rlgino/composicion-vs-herencia-4664?1 إذا كان هناك أي انتهاك، يرجى الاتصال بـ [email protected] لحذفه
أحدث البرنامج التعليمي أكثر>

تنصل: جميع الموارد المقدمة هي جزئيًا من الإنترنت. إذا كان هناك أي انتهاك لحقوق الطبع والنشر الخاصة بك أو الحقوق والمصالح الأخرى، فيرجى توضيح الأسباب التفصيلية وتقديم دليل على حقوق الطبع والنشر أو الحقوق والمصالح ثم إرسالها إلى البريد الإلكتروني: [email protected]. سوف نتعامل مع الأمر لك في أقرب وقت ممكن.

Copyright© 2022 湘ICP备2022001581号-3