---
title: "المركَّب"
type: "design-pattern"
slug: "composite"
url: "http://localhost:3000/ar/design-patterns/composite.md"
category: "الأنماط الهيكلية"
description: "المركَّب هو نمط تصميم هيكلي يتيح لك تكوين الكائنات في هياكل شجرية ثم العمل مع هذه الهياكل كما لو كانت كائنات فردية."
languages: ["java", "csharp", "cpp", "go", "php", "python", "ruby", "rust", "swift", "typescript"]
---
# المركَّب

> المركَّب هو نمط تصميم هيكلي يتيح لك تكوين الكائنات في هياكل شجرية ثم العمل مع هذه الهياكل كما لو كانت كائنات فردية.

## Intent

**المركَّب** هو نمط تصميم هيكلي يتيح لك تكوين الكائنات في هياكل شجرية ثم العمل مع هذه الهياكل كما لو كانت كائنات فردية.

## Problem

استخدام نمط المركَّب منطقي فقط عندما يمكن تمثيل النموذج الأساسي لتطبيقك كهيكل شجري.

على سبيل المثال، تخيّل أن لديك نوعين من الكائنات: `Products` و`Boxes`. يمكن أن تحتوي الـ`Box` على عدة `Products` فضلاً عن عدد من `Boxes` الأصغر. يمكن لهذه الصناديق الصغيرة بدورها أن تحتوي على بعض `Products` أو حتى `Boxes` أصغر، وهكذا دواليك.

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

قد يتضمن الطلب منتجات متنوعة معبّأة في صناديق، والتي تُعبَّأ بدورها في صناديق أكبر وهكذا. يبدو الهيكل بأكمله كشجرة مقلوبة.

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

## Solution

يقترح نمط المركَّب أن تتعامل مع `Products` و`Boxes` من خلال واجهة مشتركة تُعلن عن طريقة لحساب السعر الإجمالي.

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

يتيح لك نمط المركَّب تشغيل سلوك بشكل متكرر على جميع مكوّنات شجرة الكائنات.

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

## Structure

1. تصف واجهة **المكوّن** العمليات المشتركة لكلٍّ من العناصر البسيطة والمعقدة في الشجرة.
2. **الورقة** هي العنصر الأساسي في الشجرة الذي لا يملك عناصر فرعية.
عادةً ما تنتهي مكوّنات الورقة بالقيام بمعظم العمل الحقيقي، لأنه ليس لديها من تفوّض العمل إليه.
3. **الحاوية** (المعروفة أيضاً بـ_المركَّب_) هي عنصر يملك عناصر فرعية: أوراق أو حاويات أخرى. لا تعرف الحاوية الفئات المحددة لأبنائها. إنها تعمل مع جميع العناصر الفرعية فقط عبر واجهة المكوّن.
عند تلقّي طلب، تفوّض الحاوية العمل إلى عناصرها الفرعية، وتعالج النتائج الوسيطة ثم تعيد النتيجة النهائية إلى العميل.
4. يتعامل **العميل** مع جميع العناصر عبر واجهة المكوّن. ونتيجةً لذلك، يمكن للعميل العمل بنفس الطريقة مع كلٍّ من العناصر البسيطة والمعقدة في الشجرة.

## Pseudocode

في هذا المثال، يتيح لك نمط **المركَّب** تنفيذ تكديس الأشكال الهندسية في محرر رسومي.

مثال محرر الأشكال الهندسية.

فئة `CompoundGraphic` هي حاوية يمكنها أن تضم أي عدد من الأشكال الفرعية، بما فيها أشكال مركّبة أخرى. تمتلك الشكل المركّب نفس الطرق التي يمتلكها الشكل البسيط. ومع ذلك، بدلاً من القيام بشيء بنفسه، يمرر الشكل المركّب الطلب بشكل متكرر إلى جميع أبنائه ثم "يجمع" النتيجة.

يعمل كود العميل مع جميع الأشكال من خلال الواجهة الواحدة المشتركة بين جميع فئات الأشكال. وبذلك، لا يعرف العميل ما إذا كان يعمل مع شكل بسيط أم مركّب. يمكن للعميل العمل مع هياكل كائنات بالغة التعقيد دون الارتباط بالفئات المحددة التي تُشكّل تلك البنية.

// تُعلن واجهة المكوّن عن العمليات المشتركة لكلٍّ من
// الكائنات البسيطة والمعقدة في التركيب.
interface Graphic is
    method move(x, y)
    method draw()

// تمثّل فئة الورقة الكائنات الطرفية في التركيب. لا يمكن
// لكائن الورقة أن يمتلك كائنات فرعية. عادةً ما تقوم كائنات
// الورقة بالعمل الفعلي، في حين تفوّض كائنات المركَّب فقط
// إلى مكوّناتها الفرعية.
class Dot implements Graphic is
    field x, y

    constructor Dot(x, y) { ... }

    method move(x, y) is
        this.x += x, this.y += y

    method draw() is
        // ارسم نقطة عند X وY.

// يمكن لجميع فئات المكوّن أن تمتد من مكوّنات أخرى.
class Circle extends Dot is
    field radius

    constructor Circle(x, y, radius) { ... }

    method draw() is
        // ارسم دائرة عند X وY بنصف قطر R.

// تمثّل فئة المركَّب المكوّنات المعقدة التي قد تمتلك أبناء.
// تفوّض كائنات المركَّب عادةً العمل الفعلي لأبنائها ثم "تجمع" النتيجة.
class CompoundGraphic implements Graphic is
    field children: array of Graphic

    // يمكن لكائن المركَّب إضافة أو إزالة مكوّنات أخرى
    // (بسيطة أو معقدة) من قائمة أبنائه.
    method add(child: Graphic) is
        // أضف ابناً إلى مصفوفة الأبناء.

    method remove(child: Graphic) is
        // أزل ابناً من مصفوفة الأبناء.

    method move(x, y) is
        foreach (child in children) do
            child.move(x, y)

    // يُنفّذ المركَّب منطقه الأساسي بطريقة معينة. يتجول بشكل
    // متكرر عبر جميع أبنائه، جامعاً نتائجهم. وبما أن أبناء
    // المركَّب يمررون هذه الاستدعاءات لأبنائهم وهكذا، فإن
    // شجرة الكائنات بأكملها تُعبَر نتيجةً لذلك.
    method draw() is
        // 1. لكل مكوّن فرعي:
        //     - ارسم المكوّن.
        //     - حدّث المستطيل المحيط.
        // 2. ارسم مستطيلاً منقّطاً باستخدام
        // إحداثيات الحدود.

// يتعامل كود العميل مع جميع المكوّنات عبر واجهتها الأساسية.
// وبهذه الطريقة يمكن لكود العميل دعم مكوّنات الورقة البسيطة
// وكذلك المركّبات المعقدة.
class ImageEditor is
    field all: CompoundGraphic

    method load() is
        all = new CompoundGraphic()
        all.add(new Dot(1, 2))
        all.add(new Circle(5, 3, 10))
        // ...

    // ادمج المكوّنات المحددة في مكوّن مركّب معقد واحد.
    method groupSelected(components: array of Graphic) is
        group = new CompoundGraphic()
        foreach (component in components) do
            group.add(component)
            all.remove(component)
        all.add(group)
        // سيتم رسم جميع المكوّنات.
        all.draw()

## Applicability

استخدم نمط المركَّب عندما تضطر إلى تنفيذ هيكل كائنات يشبه الشجرة.

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

 استخدم النمط عندما تريد من كود العميل أن يعامل العناصر البسيطة والمعقدة بشكل موحّد.

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

## How to Implement

1. تأكد من أن النموذج الأساسي لتطبيقك يمكن تمثيله كهيكل شجري. حاول تقسيمه إلى عناصر بسيطة وحاويات. تذكر أن الحاويات يجب أن تكون قادرة على احتواء عناصر بسيطة وحاويات أخرى.
2. أعلن عن واجهة المكوّن بقائمة من الطرق التي تنطبق على كلٍّ من المكوّنات البسيطة والمعقدة.
3. أنشئ فئة ورقة لتمثيل العناصر البسيطة. قد يحتوي البرنامج على فئات ورقة متعددة ومختلفة.
4. أنشئ فئة حاوية لتمثيل العناصر المعقدة. في هذه الفئة، وفّر حقل مصفوفة لتخزين مراجع للعناصر الفرعية. يجب أن تكون المصفوفة قادرة على تخزين كل من الأوراق والحاويات، لذا تأكد من إعلانها بنوع واجهة المكوّن.
أثناء تنفيذ طرق واجهة المكوّن، تذكر أن الحاوية يُفترض أن تفوّض معظم العمل للعناصر الفرعية.
5. أخيراً، عرّف الطرق لإضافة وإزالة العناصر الفرعية في الحاوية.
ضع في اعتبارك أن هذه العمليات يمكن إعلانها في واجهة المكوّن. سيُنتهك هذا _مبدأ فصل الواجهة_ لأن الطرق ستكون فارغة في فئة الورقة. ومع ذلك، سيتمكن العميل من معاملة جميع العناصر بالتساوي، حتى عند تكوين الشجرة.

## Pros

* يمكنك العمل مع هياكل الشجرة المعقدة بشكل أكثر ملاءمة: استفد من تعددية الأشكال والتكرار.
* _مبدأ الفتح/الإغلاق_. يمكنك إدخال أنواع عناصر جديدة في التطبيق دون كسر الكود الحالي الذي يعمل مع شجرة الكائنات.

## Cons

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

## Relations with Other Patterns

* يمكنك استخدام [المنشئ](/ar/design-patterns/builder) عند إنشاء أشجار [المركَّب](/ar/design-patterns/composite) المعقدة لأنه يمكنك برمجة خطوات بنائه لتعمل بشكل متكرر.
* كثيراً ما يُستخدم [سلسلة المسؤولية](/ar/design-patterns/chain-of-responsibility) جنباً إلى جنب مع [المركَّب](/ar/design-patterns/composite). في هذه الحالة، عندما تتلقى مكوّنة الورقة طلباً، قد تمرره عبر سلسلة جميع المكوّنات الأصلية وصولاً إلى جذر شجرة الكائنات.
* يمكنك استخدام [المُكرّرات](/ar/design-patterns/iterator) للمرور عبر أشجار [المركَّب](/ar/design-patterns/composite).
* يمكنك استخدام [الزائر](/ar/design-patterns/visitor) لتنفيذ عملية على شجرة [المركَّب](/ar/design-patterns/composite) بأكملها.
* يمكنك تنفيذ عُقد الأوراق المشتركة في شجرة [المركَّب](/ar/design-patterns/composite) كـ[وزن خفيف](/ar/design-patterns/flyweight) لتوفير بعض ذاكرة الوصول العشوائي.
* يتشابه [المركَّب](/ar/design-patterns/composite) و[المزخرف](/ar/design-patterns/decorator) في مخططات الهيكل لأن كليهما يعتمد على التركيب المتكرر لتنظيم عدد مفتوح من الكائنات.
يشبه _المزخرف_ _المركَّب_ ولكن له مكوّن فرعي واحد فقط. ثمة فرق جوهري آخر: يضيف _المزخرف_ مسؤوليات إضافية للكائن المُغلَّف، في حين أن _المركَّب_ يجمع نتائج أبنائه فحسب.
ومع ذلك، يمكن للنمطين التعاون أيضاً: يمكنك استخدام _المزخرف_ لتوسيع سلوك كائن محدد في شجرة _المركَّب_.
* كثيراً ما تستفيد التصميمات التي تستخدم [المركَّب](/ar/design-patterns/composite) و[المزخرف](/ar/design-patterns/decorator) بشكل مكثّف من استخدام [النموذج الأولي](/ar/design-patterns/prototype). يتيح لك تطبيق النمط استنساخ الهياكل المعقدة بدلاً من إعادة بنائها من الصفر.
## Relations

**Related patterns**

- [البنّاء](/ar/design-patterns/builder.md)
- [سلسلة المسؤوليات](/ar/design-patterns/chain-of-responsibility.md)
- [المُكرِّر](/ar/design-patterns/iterator.md)
- [الزائر](/ar/design-patterns/visitor.md)
- [وزن الذبابة](/ar/design-patterns/flyweight.md)
- [المُزَخرِف](/ar/design-patterns/decorator.md)
- [النموذج الأولي (Prototype)](/ar/design-patterns/prototype.md)

## Code Examples

### java

```java
package refactoring_guru.composite.example.shapes;

import java.awt.*;

public interface Shape {
    int getX();
    int getY();
    int getWidth();
    int getHeight();
    void move(int x, int y);
    boolean isInsideBounds(int x, int y);
    void select();
    void unSelect();
    boolean isSelected();
    void paint(Graphics graphics);
}

package refactoring_guru.composite.example.shapes;

import java.awt.*;

abstract class BaseShape implements Shape {
    public int x;
    public int y;
    public Color color;
    private boolean selected = false;

    BaseShape(int x, int y, Color color) {
        this.x = x;
        this.y = y;
        this.color = color;
    }

    @Override
    public int getX() {
        return x;
    }

    @Override
    public int getY() {
        return y;
    }

    @Override
    public int getWidth() {
        return 0;
    }

    @Override
    public int getHeight() {
        return 0;
    }

    @Override
    public void move(int x, int y) {
        this.x += x;
        this.y += y;
    }

    @Override
    public boolean isInsideBounds(int x, int y) {
        return x > getX() && x < (getX() + getWidth()) &&
                y > getY() && y < (getY() + getHeight());
    }

    @Override
    public void select() {
        selected = true;
    }

    @Override
    public void unSelect() {
        selected = false;
    }

    @Override
    public boolean isSelected() {
        return selected;
    }

    void enableSelectionStyle(Graphics graphics) {
        graphics.setColor(Color.LIGHT_GRAY);

        Graphics2D g2 = (Graphics2D) graphics;
        float[] dash1 = {2.0f};
        g2.setStroke(new BasicStroke(1.0f,
                BasicStroke.CAP_BUTT,
                BasicStroke.JOIN_MITER,
                2.0f, dash1, 0.0f));
    }

    void disableSelectionStyle(Graphics graphics) {
        graphics.setColor(color);
        Graphics2D g2 = (Graphics2D) graphics;
        g2.setStroke(new BasicStroke());
    }


    @Override
    public void paint(Graphics graphics) {
        if (isSelected()) {
            enableSelectionStyle(graphics);
        }
        else {
            disableSelectionStyle(graphics);
        }

        // ...
    }
}

package refactoring_guru.composite.example.shapes;

import java.awt.*;

public class Dot extends BaseShape {
    private final int DOT_SIZE = 3;

    public Dot(int x, int y, Color color) {
        super(x, y, color);
    }

    @Override
    public int getWidth() {
        return DOT_SIZE;
    }

    @Override
    public int getHeight() {
        return DOT_SIZE;
    }

    @Override
    public void paint(Graphics graphics) {
        super.paint(graphics);
        graphics.fillRect(x - 1, y - 1, getWidth(), getHeight());
    }
}

package refactoring_guru.composite.example.shapes;

import java.awt.*;

public class Circle extends BaseShape {
    public int radius;

    public Circle(int x, int y, int radius, Color color) {
        super(x, y, color);
        this.radius = radius;
    }

    @Override
    public int getWidth() {
        return radius * 2;
    }

    @Override
    public int getHeight() {
        return radius * 2;
    }
    
    @Override
    public void paint(Graphics graphics) {
        super.paint(graphics);
        graphics.drawOval(x, y, getWidth() - 1, getHeight() - 1);
    }
}

package refactoring_guru.composite.example.shapes;

import java.awt.*;

public class Rectangle extends BaseShape {
    public int width;
    public int height;

    public Rectangle(int x, int y, int width, int height, Color color) {
        super(x, y, color);
        this.width = width;
        this.height = height;
    }

    @Override
    public int getWidth() {
        return width;
    }

    @Override
    public int getHeight() {
        return height;
    }

    @Override
    public void paint(Graphics graphics) {
        super.paint(graphics);
        graphics.drawRect(x, y, getWidth() - 1, getHeight() - 1);
    }
}

package refactoring_guru.composite.example.shapes;

import java.awt.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class CompoundShape extends BaseShape {
    protected List<Shape> children = new ArrayList<>();

    public CompoundShape(Shape... components) {
        super(0, 0, Color.BLACK);
        add(components);
    }

    public void add(Shape component) {
        children.add(component);
    }

    public void add(Shape... components) {
        children.addAll(Arrays.asList(components));
    }

    public void remove(Shape child) {
        children.remove(child);
    }

    public void remove(Shape... components) {
        children.removeAll(Arrays.asList(components));
    }

    public void clear() {
        children.clear();
    }

    @Override
    public int getX() {
        if (children.size() == 0) {
            return 0;
        }
        int x = children.get(0).getX();
        for (Shape child : children) {
            if (child.getX() < x) {
                x = child.getX();
            }
        }
        return x;
    }

    @Override
    public int getY() {
        if (children.size() == 0) {
            return 0;
        }
        int y = children.get(0).getY();
        for (Shape child : children) {
            if (child.getY() < y) {
                y = child.getY();
            }
        }
        return y;
    }

    @Override
    public int getWidth() {
        int maxWidth = 0;
        int x = getX();
        for (Shape child : children) {
            int childsRelativeX = child.getX() - x;
            int childWidth = childsRelativeX + child.getWidth();
            if (childWidth > maxWidth) {
                maxWidth = childWidth;
            }
        }
        return maxWidth;
    }

    @Override
    public int getHeight() {
        int maxHeight = 0;
        int y = getY();
        for (Shape child : children) {
            int childsRelativeY = child.getY() - y;
            int childHeight = childsRelativeY + child.getHeight();
            if (childHeight > maxHeight) {
                maxHeight = childHeight;
            }
        }
        return maxHeight;
    }

    @Override
    public void move(int x, int y) {
        for (Shape child : children) {
            child.move(x, y);
        }
    }

    @Override
    public boolean isInsideBounds(int x, int y) {
        for (Shape child : children) {
            if (child.isInsideBounds(x, y)) {
                return true;
            }
        }
        return false;
    }

    @Override
    public void unSelect() {
        super.unSelect();
        for (Shape child : children) {
            child.unSelect();
        }
    }

    public boolean selectChildAt(int x, int y) {
        for (Shape child : children) {
            if (child.isInsideBounds(x, y)) {
                child.select();
                return true;
            }
        }
        return false;
    }

    @Override
    public void paint(Graphics graphics) {
        if (isSelected()) {
            enableSelectionStyle(graphics);
            graphics.drawRect(getX() - 1, getY() - 1, getWidth() + 1, getHeight() + 1);
            disableSelectionStyle(graphics);
        }

        for (Shape child : children) {
            child.paint(graphics);
        }
    }
}

package refactoring_guru.composite.example.editor;

import refactoring_guru.composite.example.shapes.CompoundShape;
import refactoring_guru.composite.example.shapes.Shape;

import javax.swing.*;
import javax.swing.border.Border;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;

public class ImageEditor {
    private EditorCanvas canvas;
    private CompoundShape allShapes = new CompoundShape();

    public ImageEditor() {
        canvas = new EditorCanvas();
    }

    public void loadShapes(Shape... shapes) {
        allShapes.clear();
        allShapes.add(shapes);
        canvas.refresh();
    }

    private class EditorCanvas extends Canvas {
        JFrame frame;

        private static final int PADDING = 10;

        EditorCanvas() {
            createFrame();
            refresh();
            addMouseListener(new MouseAdapter() {
                @Override
                public void mousePressed(MouseEvent e) {
                    allShapes.unSelect();
                    allShapes.selectChildAt(e.getX(), e.getY());
                    e.getComponent().repaint();
                }
            });
        }

        void createFrame() {
            frame = new JFrame();
            frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
            frame.setLocationRelativeTo(null);

            JPanel contentPanel = new JPanel();
            Border padding = BorderFactory.createEmptyBorder(PADDING, PADDING, PADDING, PADDING);
            contentPanel.setBorder(padding);
            frame.setContentPane(contentPanel);

            frame.add(this);
            frame.setVisible(true);
            frame.getContentPane().setBackground(Color.LIGHT_GRAY);
        }

        public int getWidth() {
            return allShapes.getX() + allShapes.getWidth() + PADDING;
        }

        public int getHeight() {
            return allShapes.getY() + allShapes.getHeight() + PADDING;
        }

        void refresh() {
            this.setSize(getWidth(), getHeight());
            frame.pack();
        }

        public void paint(Graphics graphics) {
            allShapes.paint(graphics);
        }
    }
}

package refactoring_guru.composite.example;

import refactoring_guru.composite.example.editor.ImageEditor;
import refactoring_guru.composite.example.shapes.Circle;
import refactoring_guru.composite.example.shapes.CompoundShape;
import refactoring_guru.composite.example.shapes.Dot;
import refactoring_guru.composite.example.shapes.Rectangle;

import java.awt.*;

public class Demo {
    public static void main(String[] args) {
        ImageEditor editor = new ImageEditor();

        editor.loadShapes(
                new Circle(10, 10, 10, Color.BLUE),

                new CompoundShape(
                    new Circle(110, 110, 50, Color.RED),
                    new Dot(160, 160, Color.RED)
                ),

                new CompoundShape(
                        new Rectangle(250, 250, 100, 100, Color.GREEN),
                        new Dot(240, 240, Color.GREEN),
                        new Dot(240, 360, Color.GREEN),
                        new Dot(360, 360, Color.GREEN),
                        new Dot(360, 240, Color.GREEN)
                )
        );
    }
}
```

### csharp

```csharp
using System;
using System.Collections.Generic;

namespace RefactoringGuru.DesignPatterns.Composite.Conceptual
{
    // تُعلن فئة المكوّن الأساسية عن العمليات المشتركة لكلٍّ من
    // الكائنات البسيطة والمعقدة في التركيب.
    abstract class Component
    {
        public Component() { }

        // قد تُنفّذ فئة المكوّن الأساسية بعض السلوكيات الافتراضية أو تتركها
        // للفئات المحددة (بتعريف الطريقة المحتوية للسلوك كـ"abstract").
        public abstract string Operation();

        // في بعض الحالات، قد يكون من المفيد تعريف عمليات إدارة الأبناء
        // مباشرةً في فئة المكوّن الأساسية. بهذه الطريقة، لن تحتاج
        // إلى كشف أي فئات مكوّن محددة لكود العميل، حتى أثناء
        // تجميع شجرة الكائنات. الجانب السلبي هو أن هذه الطرق
        // ستكون فارغة لمكوّنات مستوى الورقة.
        public virtual void Add(Component component)
        {
            throw new NotImplementedException();
        }

        public virtual void Remove(Component component)
        {
            throw new NotImplementedException();
        }

        // يمكنك توفير طريقة تتيح لكود العميل معرفة ما إذا كان
        // المكوّن يمكنه أن ينجب أبناء.
        public virtual bool IsComposite()
        {
            return true;
        }
    }

    // تمثّل فئة الورقة الكائنات الطرفية في التركيب. لا يمكن لورقة
    // أن تمتلك أي أبناء.
    //
    // عادةً ما تقوم كائنات الورقة بالعمل الفعلي، في حين تفوّض كائنات
    // المركَّب فقط إلى مكوّناتها الفرعية.
    class Leaf : Component
    {
        public override string Operation()
        {
            return "Leaf";
        }

        public override bool IsComposite()
        {
            return false;
        }
    }

    // تمثّل فئة المركَّب المكوّنات المعقدة التي قد تمتلك أبناء.
    // عادةً ما تفوّض كائنات المركَّب العمل الفعلي لأبنائها ثم "تجمع" النتيجة.
    class Composite : Component
    {
        protected List<Component> _children = new List<Component>();
        
        public override void Add(Component component)
        {
            this._children.Add(component);
        }

        public override void Remove(Component component)
        {
            this._children.Remove(component);
        }

        // يُنفّذ المركَّب منطقه الأساسي بطريقة معينة. يتجول بشكل
        // متكرر عبر جميع أبنائه، جامعاً نتائجهم. وبما أن أبناء المركَّب
        // يمررون هذه الاستدعاءات لأبنائهم وهكذا، فإن شجرة الكائنات
        // بأكملها تُعبَر نتيجةً لذلك.
        public override string Operation()
        {
            int i = 0;
            string result = "Branch(";

            foreach (Component component in this._children)
            {
                result += component.Operation();
                if (i != this._children.Count - 1)
                {
                    result += "+";
                }
                i++;
            }
            
            return result + ")";
        }
    }

    class Client
    {
        // يتعامل كود العميل مع جميع المكوّنات عبر الواجهة الأساسية.
        public void ClientCode(Component leaf)
        {
            Console.WriteLine($"RESULT: {leaf.Operation()}\n");
        }

        // بفضل كون عمليات إدارة الأبناء مُعلنة في فئة المكوّن الأساسية،
        // يمكن لكود العميل العمل مع أي مكوّن، بسيط أو معقد، دون
        // الاعتماد على فئاته المحددة.
        public void ClientCode2(Component component1, Component component2)
        {
            if (component1.IsComposite())
            {
                component1.Add(component2);
            }
            
            Console.WriteLine($"RESULT: {component1.Operation()}");
        }
    }
    
    class Program
    {
        static void Main(string[] args)
        {
            Client client = new Client();

            // بهذه الطريقة يمكن لكود العميل دعم مكوّنات الورقة البسيطة...
            Leaf leaf = new Leaf();
            Console.WriteLine("Client: I get a simple component:");
            client.ClientCode(leaf);

            // ...وكذلك المركّبات المعقدة.
            Composite tree = new Composite();
            Composite branch1 = new Composite();
            branch1.Add(new Leaf());
            branch1.Add(new Leaf());
            Composite branch2 = new Composite();
            branch2.Add(new Leaf());
            tree.Add(branch1);
            tree.Add(branch2);
            Console.WriteLine("Client: Now I've got a composite tree:");
            client.ClientCode(tree);

            Console.Write("Client: I don't need to check the components classes even when managing the tree:\n");
            client.ClientCode2(tree, leaf);
        }
    }
}

Client: I get a simple component:
RESULT: Leaf

Client: Now I've got a composite tree:
RESULT: Branch(Branch(Leaf+Leaf)+Branch(Leaf))

Client: I don't need to check the components classes even when managing the tree:
RESULT: Branch(Branch(Leaf+Leaf)+Branch(Leaf)+Leaf)
```

### cpp

```cpp
#include <algorithm>
#include <iostream>
#include <list>
#include <string>
/**
 * تُعلن فئة المكوّن الأساسية عن العمليات المشتركة لكلٍّ من الكائنات
 * البسيطة والمعقدة في التركيب.
 */
class Component {
  /**
   * @var Component
   */
 protected:
  Component *parent_;
  /**
   * يمكن اختياريًا أن تُعلن فئة المكوّن الأساسية عن واجهة لضبط والوصول
   * لوالد المكوّن في هيكل شجري. يمكنها أيضاً توفير تنفيذ افتراضي لهذه الطرق.
   */
 public:
  virtual ~Component() {}
  void SetParent(Component *parent) {
    this->parent_ = parent;
  }
  Component *GetParent() const {
    return this->parent_;
  }
  /**
   * في بعض الحالات، قد يكون من المفيد تعريف عمليات إدارة الأبناء مباشرةً
   * في فئة المكوّن الأساسية. بهذه الطريقة، لن تحتاج إلى كشف أي فئات
   * مكوّن محددة لكود العميل، حتى أثناء تجميع شجرة الكائنات. الجانب
   * السلبي هو أن هذه الطرق ستكون فارغة لمكوّنات مستوى الورقة.
   */
  virtual void Add(Component *component) {}
  virtual void Remove(Component *component) {}
  /**
   * يمكنك توفير طريقة تتيح لكود العميل معرفة ما إذا كان المكوّن
   * يمكنه أن ينجب أبناء.
   */
  virtual bool IsComposite() const {
    return false;
  }
  /**
   * قد تُنفّذ فئة المكوّن الأساسية بعض السلوكيات الافتراضية أو تتركها
   * للفئات المحددة (بتعريف الطريقة كـ"abstract").
   */
  virtual std::string Operation() const = 0;
};
/**
 * تمثّل فئة الورقة الكائنات الطرفية في التركيب. لا يمكن لورقة
 * أن تمتلك أي أبناء.
 *
 * عادةً ما تقوم كائنات الورقة بالعمل الفعلي، في حين تفوّض كائنات
 * المركَّب فقط إلى مكوّناتها الفرعية.
 */
class Leaf : public Component {
 public:
  std::string Operation() const override {
    return "Leaf";
  }
};
/**
 * تمثّل فئة المركَّب المكوّنات المعقدة التي قد تمتلك أبناء.
 * عادةً ما تفوّض كائنات المركَّب العمل الفعلي لأبنائها ثم "تجمع" النتيجة.
 */
class Composite : public Component {
  /**
   * @var \SplObjectStorage
   */
 protected:
  std::list<Component *> children_;

 public:
  /**
   * يمكن لكائن المركَّب إضافة أو إزالة مكوّنات أخرى (بسيطة أو معقدة)
   * من قائمة أبنائه.
   */
  void Add(Component *component) override {
    this->children_.push_back(component);
    component->SetParent(this);
  }
  /**
   * ضع في اعتبارك أن هذه الطريقة تزيل المؤشر من القائمة لكنها لا تحرر
   * الذاكرة، عليك فعل ذلك يدوياً أو من الأفضل استخدام المؤشرات الذكية.
   */
  void Remove(Component *component) override {
    children_.remove(component);
    component->SetParent(nullptr);
  }
  bool IsComposite() const override {
    return true;
  }
  /**
   * يُنفّذ المركَّب منطقه الأساسي بطريقة معينة. يتجول بشكل متكرر عبر
   * جميع أبنائه، جامعاً نتائجهم. وبما أن أبناء المركَّب يمررون هذه
   * الاستدعاءات لأبنائهم وهكذا، فإن شجرة الكائنات بأكملها تُعبَر
   * نتيجةً لذلك.
   */
  std::string Operation() const override {
    std::string result;
    for (const Component *c : children_) {
      if (c == children_.back()) {
        result += c->Operation();
      } else {
        result += c->Operation() + "+";
      }
    }
    return "Branch(" + result + ")";
  }
};
/**
 * يتعامل كود العميل مع جميع المكوّنات عبر الواجهة الأساسية.
 */
void ClientCode(Component *component) {
  // ...
  std::cout << "RESULT: " << component->Operation();
  // ...
}

/**
 * بفضل كون عمليات إدارة الأبناء مُعلنة في فئة المكوّن الأساسية،
 * يمكن لكود العميل العمل مع أي مكوّن، بسيط أو معقد، دون الاعتماد
 * على فئاته المحددة.
 */
void ClientCode2(Component *component1, Component *component2) {
  // ...
  if (component1->IsComposite()) {
    component1->Add(component2);
  }
  std::cout << "RESULT: " << component1->Operation();
  // ...
}

/**
 * بهذه الطريقة يمكن لكود العميل دعم مكوّنات الورقة البسيطة...
 */

int main() {
  Component *simple = new Leaf;
  std::cout << "Client: I've got a simple component:\n";
  ClientCode(simple);
  std::cout << "\n\n";
  /**
   * ...وكذلك المركّبات المعقدة.
   */

  Component *tree = new Composite;
  Component *branch1 = new Composite;

  Component *leaf_1 = new Leaf;
  Component *leaf_2 = new Leaf;
  Component *leaf_3 = new Leaf;
  branch1->Add(leaf_1);
  branch1->Add(leaf_2);
  Component *branch2 = new Composite;
  branch2->Add(leaf_3);
  tree->Add(branch1);
  tree->Add(branch2);
  std::cout << "Client: Now I've got a composite tree:\n";
  ClientCode(tree);
  std::cout << "\n\n";

  std::cout << "Client: I don't need to check the components classes even when managing the tree:\n";
  ClientCode2(tree, simple);
  std::cout << "\n";

  delete simple;
  delete tree;
  delete branch1;
  delete branch2;
  delete leaf_1;
  delete leaf_2;
  delete leaf_3;

  return 0;
}

Client: I've got a simple component:
RESULT: Leaf

Client: Now I've got a composite tree:
RESULT: Branch(Branch(Leaf+Leaf)+Branch(Leaf))

Client: I don't need to check the components classes even when managing the tree:
RESULT: Branch(Branch(Leaf+Leaf)+Branch(Leaf)+Leaf)
```

### go

```go
package main

type Component interface {
	search(string)
}

package main

import "fmt"

type Folder struct {
	components []Component
	name       string
}

func (f *Folder) search(keyword string) {
	fmt.Printf("Serching recursively for keyword %s in folder %s\n", keyword, f.name)
	for _, composite := range f.components {
		composite.search(keyword)
	}
}

func (f *Folder) add(c Component) {
	f.components = append(f.components, c)
}

package main

import "fmt"

type File struct {
	name string
}

func (f *File) search(keyword string) {
	fmt.Printf("Searching for keyword %s in file %s\n", keyword, f.name)
}

func (f *File) getName() string {
	return f.name
}

package main

func main() {
	file1 := &File{name: "File1"}
	file2 := &File{name: "File2"}
	file3 := &File{name: "File3"}

	folder1 := &Folder{
		name: "Folder1",
	}

	folder1.add(file1)

	folder2 := &Folder{
		name: "Folder2",
	}
	folder2.add(file2)
	folder2.add(file3)
	folder2.add(folder1)

	folder2.search("rose")
}

Serching recursively for keyword rose in folder Folder2
Searching for keyword rose in file File2
Searching for keyword rose in file File3
Serching recursively for keyword rose in folder Folder1
Searching for keyword rose in file File1
```

### php

```php
<?php

namespace RefactoringGuru\Composite\Conceptual;

/**
 * تُعلن فئة المكوّن الأساسية عن العمليات المشتركة لكلٍّ من الكائنات
 * البسيطة والمعقدة في التركيب.
 */
abstract class Component
{
    /**
     * @var Component|null
     */
    protected $parent;

    /**
     * يمكن اختياريًا أن تُعلن فئة المكوّن الأساسية عن واجهة لضبط والوصول
     * لوالد المكوّن في هيكل شجري. يمكنها أيضاً توفير تنفيذ افتراضي لهذه الطرق.
     */
    public function setParent(?Component $parent)
    {
        $this->parent = $parent;
    }

    public function getParent(): Component
    {
        return $this->parent;
    }

    /**
     * في بعض الحالات، قد يكون من المفيد تعريف عمليات إدارة الأبناء مباشرةً
     * في فئة المكوّن الأساسية. بهذه الطريقة، لن تحتاج إلى كشف أي فئات
     * مكوّن محددة لكود العميل، حتى أثناء تجميع شجرة الكائنات. الجانب السلبي
     * هو أن هذه الطرق ستكون فارغة لمكوّنات مستوى الورقة.
     */
    public function add(Component $component): void
    {
    }

    public function remove(Component $component): void
    {
    }

    /**
     * يمكنك توفير طريقة تتيح لكود العميل معرفة ما إذا كان المكوّن
     * يمكنه أن ينجب أبناء.
     */
    public function isComposite(): bool
    {
        return false;
    }

    /**
     * قد تُنفّذ فئة المكوّن الأساسية بعض السلوكيات الافتراضية أو تتركها
     * للفئات المحددة (بتعريف الطريقة المحتوية للسلوك كـ"abstract").
     */
    abstract public function operation(): string;
}

/**
 * تمثّل فئة الورقة الكائنات الطرفية في التركيب. لا يمكن لورقة
 * أن تمتلك أي أبناء.
 *
 * عادةً ما تقوم كائنات الورقة بالعمل الفعلي، في حين تفوّض كائنات
 * المركَّب فقط إلى مكوّناتها الفرعية.
 */
class Leaf extends Component
{
    public function operation(): string
    {
        return "Leaf";
    }
}

/**
 * تمثّل فئة المركَّب المكوّنات المعقدة التي قد تمتلك أبناء.
 * عادةً ما تفوّض كائنات المركَّب العمل الفعلي لأبنائها ثم "تجمع" النتيجة.
 */
class Composite extends Component
{
    /**
     * @var \SplObjectStorage
     */
    protected $children;

    public function __construct()
    {
        $this->children = new \SplObjectStorage();
    }

    /**
     * يمكن لكائن المركَّب إضافة أو إزالة مكوّنات أخرى (بسيطة أو معقدة)
     * من قائمة أبنائه.
     */
    public function add(Component $component): void
    {
        $this->children->attach($component);
        $component->setParent($this);
    }

    public function remove(Component $component): void
    {
        $this->children->detach($component);
        $component->setParent(null);
    }

    public function isComposite(): bool
    {
        return true;
    }

    /**
     * يُنفّذ المركَّب منطقه الأساسي بطريقة معينة. يتجول بشكل متكرر عبر
     * جميع أبنائه، جامعاً نتائجهم. وبما أن أبناء المركَّب يمررون هذه
     * الاستدعاءات لأبنائهم وهكذا، فإن شجرة الكائنات بأكملها تُعبَر
     * نتيجةً لذلك.
     */
    public function operation(): string
    {
        $results = [];
        foreach ($this->children as $child) {
            $results[] = $child->operation();
        }

        return "Branch(" . implode("+", $results) . ")";
    }
}

/**
 * يتعامل كود العميل مع جميع المكوّنات عبر الواجهة الأساسية.
 */
function clientCode(Component $component)
{
    // ...

    echo "RESULT: " . $component->operation();

    // ...
}

/**
 * بهذه الطريقة يمكن لكود العميل دعم مكوّنات الورقة البسيطة...
 */
$simple = new Leaf();
echo "Client: I've got a simple component:\n";
clientCode($simple);
echo "\n\n";

/**
 * ...as well as the complex composites.
 */
$tree = new Composite();
$branch1 = new Composite();
$branch1->add(new Leaf());
$branch1->add(new Leaf());
$branch2 = new Composite();
$branch2->add(new Leaf());
$tree->add($branch1);
$tree->add($branch2);
echo "Client: Now I've got a composite tree:\n";
clientCode($tree);
echo "\n\n";

/**
 * بفضل كون عمليات إدارة الأبناء مُعلنة في فئة المكوّن الأساسية،
 * يمكن لكود العميل العمل مع أي مكوّن، بسيط أو معقد، دون الاعتماد
 * على فئاته المحددة.
 */
function clientCode2(Component $component1, Component $component2)
{
    // ...

    if ($component1->isComposite()) {
        $component1->add($component2);
    }
    echo "RESULT: " . $component1->operation();

    // ...
}

echo "Client: I don't need to check the components classes even when managing the tree:\n";
clientCode2($tree, $simple);

Client: I get a simple component:
RESULT: Leaf

Client: Now I get a composite tree:
RESULT: Branch(Branch(Leaf+Leaf)+Branch(Leaf))

Client: I don't need to check the components classes even when managing the tree::
RESULT: Branch(Branch(Leaf+Leaf)+Branch(Leaf)+Leaf)

<?php

namespace RefactoringGuru\Composite\RealWorld;

/**
 * تُعلن فئة المكوّن الأساسية عن واجهة لجميع المكوّنات المحددة،
 * البسيطة والمعقدة على حدٍّ سواء.
 *
 * في مثالنا، سنركّز على سلوك عرض عناصر DOM.
 */
abstract class FormElement
{
    /**
     * يمكننا توقّع أن جميع عناصر DOM تحتاج هذه الحقول الثلاثة.
     */
    protected $name;
    protected $title;
    protected $data;

    public function __construct(string $name, string $title)
    {
        $this->name = $name;
        $this->title = $title;
    }

    public function getName(): string
    {
        return $this->name;
    }

    public function setData($data): void
    {
        $this->data = $data;
    }

    public function getData(): array
    {
        return $this->data;
    }

    /**
     * يجب على كل عنصر DOM محدد توفير تنفيذ العرض الخاص به، لكن
     * يمكننا افتراض بأمان أن جميعها تُعيد سلاسل نصية.
     */
    abstract public function render(): string;
}

/**
 * هذا مكوّن ورقة. مثل جميع الأوراق، لا يمكنه أن يمتلك أبناء.
 */
class Input extends FormElement
{
    private $type;

    public function __construct(string $name, string $title, string $type)
    {
        parent::__construct($name, $title);
        $this->type = $type;
    }

    /**
     * بما أن مكوّنات الورقة لا تمتلك أبناء يتولّون جزءاً من العمل عنها،
     * فعادةً ما تضطلع الأوراق بمعظم العمل الشاق ضمن نمط المركَّب.
     */
    public function render(): string
    {
        return "<label for=\"{$this->name}\">{$this->title}</label>\n" .
            "<input name=\"{$this->name}\" type=\"{$this->type}\" value=\"{$this->data}\">\n";
    }
}

/**
 * تُنفّذ فئة المركَّب الأساسية البنية التحتية لإدارة كائنات الأبناء،
 * تُعاد استخدامها من قِبَل جميع المركّبات المحددة.
 */
abstract class FieldComposite extends FormElement
{
    /**
     * @var FormElement[]
     */
    protected $fields = [];

    /**
     * الطرق لإضافة/إزالة الكائنات الفرعية.
     */
    public function add(FormElement $field): void
    {
        $name = $field->getName();
        $this->fields[$name] = $field;
    }

    public function remove(FormElement $component): void
    {
        $this->fields = array_filter($this->fields, function ($child) use ($component) {
            return $child != $component;
        });
    }

    /**
     * بينما تؤدي طريقة الورقة المهمة مباشرةً، فإن طريقة المركَّب تحتاج
     * دائماً تقريباً إلى مراعاة كائناتها الفرعية.
     *
     * في هذه الحالة، يمكن للمركَّب قبول البيانات المهيكلة.
     *
     * @param array $data
     */
    public function setData($data): void
    {
        foreach ($this->fields as $name => $field) {
            if (isset($data[$name])) {
                $field->setData($data[$name]);
            }
        }
    }

    /**
     * ينطبق نفس المنطق على دالة الاسترجاع. تُعيد البيانات المهيكلة
     * للمركَّب نفسه (إن وجدت) وجميع بيانات الأبناء.
     */
    public function getData(): array
    {
        $data = [];

        foreach ($this->fields as $name => $field) {
            $data[$name] = $field->getData();
        }

        return $data;
    }

    /**
     * يجمع التنفيذ الأساسي لعرض المركَّب ببساطة نتائج جميع الأبناء.
     * ستتمكن المركّبات المحددة من إعادة استخدام هذا التنفيذ في
     * تنفيذات العرض الحقيقية الخاصة بها.
     */
    public function render(): string
    {
        $output = "";

        foreach ($this->fields as $name => $field) {
            $output .= $field->render();
        }

        return $output;
    }
}

/**
 * عنصر fieldset هو مركَّب محدد.
 */
class Fieldset extends FieldComposite
{
    public function render(): string
    {
        // لاحظ كيف يتم دمج نتيجة عرض الأبناء المجمّعة في وسم fieldset.
        $output = parent::render();

        return "<fieldset><legend>{$this->title}</legend>\n$output</fieldset>\n";
    }
}

/**
 * وكذلك عنصر Form.
 */
class Form extends FieldComposite
{
    protected $url;

    public function __construct(string $name, string $title, string $url)
    {
        parent::__construct($name, $title);
        $this->url = $url;
    }

    public function render(): string
    {
        $output = parent::render();
        return "<form action=\"{$this->url}\">\n<h3>{$this->title}</h3>\n$output</form>\n";
    }
}

/**
 * يحصل كود العميل على واجهة ملائمة لبناء هياكل شجرية معقدة.
 */
function getProductForm(): FormElement
{
    $form = new Form('product', "Add product", "/product/add");
    $form->add(new Input('name', "Name", 'text'));
    $form->add(new Input('description', "Description", 'text'));

    $picture = new Fieldset('photo', "Product photo");
    $picture->add(new Input('caption', "Caption", 'text'));
    $picture->add(new Input('image', "Image", 'file'));
    $form->add($picture);

    return $form;
}

/**
 * يمكن ملء هيكل النموذج ببيانات من مصادر مختلفة. لا يضطر العميل
 * إلى المرور عبر جميع حقول النموذج لتعيين البيانات لحقول مختلفة
 * لأن النموذج نفسه يمكنه التعامل مع ذلك.
 */
function loadProductData(FormElement $form)
{
    $data = [
        'name' => 'Apple MacBook',
        'description' => 'A decent laptop.',
        'photo' => [
            'caption' => 'Front photo.',
            'image' => 'photo1.png',
        ],
    ];

    $form->setData($data);
}

/**
 * يمكن لكود العميل العمل مع عناصر النموذج باستخدام الواجهة المجردة.
 * بهذه الطريقة، لا يهم ما إذا كان العميل يعمل مع مكوّن بسيط
 * أو شجرة مركَّب معقدة.
 */
function renderProduct(FormElement $form)
{
    // ..

    echo $form->render();

    // ..
}

$form = getProductForm();
loadProductData($form);
renderProduct($form);

<form action="/product/add">
<h3>Add product</h3>
<label for="name">Name</label>
<input name="name" type="text" value="Apple MacBook">
<label for="description">Description</label>
<input name="description" type="text" value="A decent laptop.">
<fieldset><legend>Product photo</legend>
<label for="caption">Caption</label>
<input name="caption" type="text" value="Front photo.">
<label for="image">Image</label>
<input name="image" type="file" value="photo1.png">
</fieldset>
</form>
```

### python

```python
from __future__ import annotations
from abc import ABC, abstractmethod
from typing import List


class Component(ABC):
    """
    تُعلن فئة المكوّن الأساسية عن العمليات المشتركة لكلٍّ من الكائنات
    البسيطة والمعقدة في التركيب.
    """

    @property
    def parent(self) -> Component:
        return self._parent

    @parent.setter
    def parent(self, parent: Component):
        """
        يمكن اختياريًا أن تُعلن فئة المكوّن الأساسية عن واجهة لضبط والوصول
        لوالد المكوّن في هيكل شجري. يمكنها أيضاً توفير تنفيذ افتراضي لهذه الطرق.
        """

        self._parent = parent

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

    def add(self, component: Component) -> None:
        pass

    def remove(self, component: Component) -> None:
        pass

    def is_composite(self) -> bool:
        """
        يمكنك توفير طريقة تتيح لكود العميل معرفة ما إذا كان المكوّن
        يمكنه أن ينجب أبناء.
        """

        return False

    @abstractmethod
    def operation(self) -> str:
        """
        قد تُنفّذ فئة المكوّن الأساسية بعض السلوكيات الافتراضية أو تتركها
        للفئات المحددة (بتعريف الطريقة المحتوية للسلوك كـ"abstract").
        """

        pass


class Leaf(Component):
    """
    تمثّل فئة الورقة الكائنات الطرفية في التركيب. لا يمكن لورقة
    أن تمتلك أي أبناء.

    عادةً ما تقوم كائنات الورقة بالعمل الفعلي، في حين تفوّض كائنات
    المركَّب فقط إلى مكوّناتها الفرعية.
    """

    def operation(self) -> str:
        return "Leaf"


class Composite(Component):
    """
    تمثّل فئة المركَّب المكوّنات المعقدة التي قد تمتلك أبناء. عادةً ما
    تفوّض كائنات المركَّب العمل الفعلي لأبنائها ثم "تجمع" النتيجة.
    """

    def __init__(self) -> None:
        self._children: List[Component] = []

    """
    يمكن لكائن المركَّب إضافة أو إزالة مكوّنات أخرى (بسيطة أو معقدة)
    من قائمة أبنائه.
    """

    def add(self, component: Component) -> None:
        self._children.append(component)
        component.parent = self

    def remove(self, component: Component) -> None:
        self._children.remove(component)
        component.parent = None

    def is_composite(self) -> bool:
        return True

    def operation(self) -> str:
        """
        يُنفّذ المركَّب منطقه الأساسي بطريقة معينة. يتجول بشكل متكرر عبر
        جميع أبنائه، جامعاً نتائجهم. وبما أن أبناء المركَّب يمررون هذه
        الاستدعاءات لأبنائهم وهكذا، فإن شجرة الكائنات بأكملها تُعبَر
        نتيجةً لذلك.
        """

        results = []
        for child in self._children:
            results.append(child.operation())
        return f"Branch({'+'.join(results)})"


def client_code(component: Component) -> None:
    """
    يتعامل كود العميل مع جميع المكوّنات عبر الواجهة الأساسية.
    """

    print(f"RESULT: {component.operation()}", end="")


def client_code2(component1: Component, component2: Component) -> None:
    """
    بفضل كون عمليات إدارة الأبناء مُعلنة في فئة المكوّن الأساسية،
    يمكن لكود العميل العمل مع أي مكوّن، بسيط أو معقد، دون الاعتماد
    على فئاته المحددة.
    """

    if component1.is_composite():
        component1.add(component2)

    print(f"RESULT: {component1.operation()}", end="")


if __name__ == "__main__":
    # بهذه الطريقة يمكن لكود العميل دعم مكوّنات الورقة البسيطة...
    simple = Leaf()
    print("Client: I've got a simple component:")
    client_code(simple)
    print("\n")

    # ...وكذلك المركّبات المعقدة.
    tree = Composite()

    branch1 = Composite()
    branch1.add(Leaf())
    branch1.add(Leaf())

    branch2 = Composite()
    branch2.add(Leaf())

    tree.add(branch1)
    tree.add(branch2)

    print("Client: Now I've got a composite tree:")
    client_code(tree)
    print("\n")

    print("Client: I don't need to check the components classes even when managing the tree:")
    client_code2(tree, simple)

Client: I've got a simple component:
RESULT: Leaf

Client: Now I've got a composite tree:
RESULT: Branch(Branch(Leaf+Leaf)+Branch(Leaf))

Client: I don't need to check the components classes even when managing the tree:
RESULT: Branch(Branch(Leaf+Leaf)+Branch(Leaf)+Leaf)
```

### ruby

```ruby
# تُعلن فئة المكوّن الأساسية عن العمليات المشتركة لكلٍّ من الكائنات
# البسيطة والمعقدة في التركيب.
class Component
  # @return [Component]
  def parent
    @parent
  end

  # يمكن اختياريًا أن تُعلن فئة المكوّن الأساسية عن واجهة لضبط والوصول
  # لوالد المكوّن في هيكل شجري. يمكنها أيضاً توفير تنفيذ افتراضي لهذه الطرق.
  def parent=(parent)
    @parent = parent
  end

  # في بعض الحالات، قد يكون من المفيد تعريف عمليات إدارة الأبناء مباشرةً
  # في فئة المكوّن الأساسية. بهذه الطريقة، لن تحتاج إلى كشف أي فئات
  # مكوّن محددة لكود العميل، حتى أثناء تجميع شجرة الكائنات. الجانب
  # السلبي هو أن هذه الطرق ستكون فارغة لمكوّنات مستوى الورقة.
  def add(component)
    raise NotImplementedError, "#{self.class} has not implemented method '#{__method__}'"
  end

  # @abstract
  #
  # @param [Component] component
  def remove(component)
    raise NotImplementedError, "#{self.class} has not implemented method '#{__method__}'"
  end

  # يمكنك توفير طريقة تتيح لكود العميل معرفة ما إذا كان المكوّن
  # يمكنه أن ينجب أبناء.
  def composite?
    false
  end

  # قد تُنفّذ فئة المكوّن الأساسية بعض السلوكيات الافتراضية أو تتركها
  # للفئات المحددة (بتعريف الطريقة المحتوية للسلوك كـ"abstract").
  def operation
    raise NotImplementedError, "#{self.class} has not implemented method '#{__method__}'"
  end
end

# تمثّل فئة الورقة الكائنات الطرفية في التركيب. لا يمكن لورقة
# أن تمتلك أي أبناء.
#
# عادةً ما تقوم كائنات الورقة بالعمل الفعلي، في حين تفوّض كائنات
# المركَّب فقط إلى مكوّناتها الفرعية.
class Leaf < Component
  # return [String]
  def operation
    'Leaf'
  end
end

# تمثّل فئة المركَّب المكوّنات المعقدة التي قد تمتلك أبناء. عادةً ما
# تفوّض كائنات المركَّب العمل الفعلي لأبنائها ثم "تجمع" النتيجة.
class Composite < Component
  def initialize
    @children = []
  end

  # يمكن لكائن المركَّب إضافة أو إزالة مكوّنات أخرى (بسيطة أو معقدة)
  # من قائمة أبنائه.

  # @param [Component] component
  def add(component)
    @children.append(component)
    component.parent = self
  end

  # @param [Component] component
  def remove(component)
    @children.remove(component)
    component.parent = nil
  end

  # @return [Boolean]
  def composite?
    true
  end

  # يُنفّذ المركَّب منطقه الأساسي بطريقة معينة. يتجول بشكل متكرر عبر
  # جميع أبنائه، جامعاً نتائجهم. وبما أن أبناء المركَّب يمررون هذه
  # الاستدعاءات لأبنائهم وهكذا، فإن شجرة الكائنات بأكملها تُعبَر
  # نتيجةً لذلك.
  def operation
    results = []
    @children.each { |child| results.append(child.operation) }
    "Branch(#{results.join('+')})"
  end
end

# يتعامل كود العميل مع جميع المكوّنات عبر الواجهة الأساسية.
def client_code(component)
  puts "RESULT: #{component.operation}"
end

# بفضل كون عمليات إدارة الأبناء مُعلنة في فئة المكوّن الأساسية،
# يمكن لكود العميل العمل مع أي مكوّن، بسيط أو معقد، دون الاعتماد
# على فئاته المحددة.
def client_code2(component1, component2)
  component1.add(component2) if component1.composite?

  print "RESULT: #{component1.operation}"
end

# بهذه الطريقة يمكن لكود العميل دعم مكوّنات الورقة البسيطة...
simple = Leaf.new
puts 'Client: I\'ve got a simple component:'
client_code(simple)
puts "\n"

# ...وكذلك المركّبات المعقدة.
tree = Composite.new

branch1 = Composite.new
branch1.add(Leaf.new)
branch1.add(Leaf.new)

branch2 = Composite.new
branch2.add(Leaf.new)

tree.add(branch1)
tree.add(branch2)

puts 'Client: Now I\'ve got a composite tree:'
client_code(tree)
puts "\n"

puts 'Client: I don\'t need to check the components classes even when managing the tree:'
client_code2(tree, simple)

Client: I've got a simple component:
RESULT: Leaf

Client: Now I've got a composite tree:
RESULT: Branch(Branch(Leaf+Leaf)+Branch(Leaf))

Client: I don't need to check the components classes even when managing the tree:
RESULT: Branch(Branch(Leaf+Leaf)+Branch(Leaf)+Leaf)
```

### rust

```rust
mod file;
mod folder;

pub use file::File;
pub use folder::Folder;

pub trait Component {
    fn search(&self, keyword: &str);
}

use super::Component;

pub struct File {
    name: &'static str,
}

impl File {
    pub fn new(name: &'static str) -> Self {
        Self { name }
    }
}

impl Component for File {
    fn search(&self, keyword: &str) {
        println!("Searching for keyword {} in file {}", keyword, self.name);
    }
}

use super::Component;

pub struct Folder {
    name: &'static str,
    components: Vec<Box<dyn Component>>,
}

impl Folder {
    pub fn new(name: &'static str) -> Self {
        Self {
            name,
            components: vec![],
        }
    }

    pub fn add(&mut self, component: impl Component + 'static) {
        self.components.push(Box::new(component));
    }
}

impl Component for Folder {
    fn search(&self, keyword: &str) {
        println!(
            "Searching recursively for keyword {} in folder {}",
            keyword, self.name
        );

        for component in self.components.iter() {
            component.search(keyword);
        }
    }
}

mod fs;

use fs::{Component, File, Folder};

fn main() {
    let file1 = File::new("File 1");
    let file2 = File::new("File 2");
    let file3 = File::new("File 3");

    let mut folder1 = Folder::new("Folder 1");
    folder1.add(file1);

    let mut folder2 = Folder::new("Folder 2");
    folder2.add(file2);
    folder2.add(file3);
    folder2.add(folder1);

    folder2.search("rose");
}

Searching recursively for keyword rose in folder Folder 2
Searching for keyword rose in file File 2
Searching for keyword rose in file File 3
Searching recursively for keyword rose in folder Folder 1
Searching for keyword rose in file File 1
------------------------------------
```

### swift

```swift
import XCTest

/// تُعلن فئة المكوّن الأساسية عن العمليات المشتركة لكلٍّ من الكائنات
/// البسيطة والمعقدة في التركيب.
protocol Component {

    /// يمكن اختياريًا أن تُعلن فئة المكوّن الأساسية عن طرق لضبط والوصول
    /// لوالد المكوّن في هيكل شجري. يمكنها أيضاً توفير تنفيذ افتراضي لهذه الطرق.
    var parent: Component? { get set }

    /// في بعض الحالات، قد يكون من المفيد تعريف عمليات إدارة الأبناء مباشرةً
    /// في فئة المكوّن الأساسية. بهذه الطريقة، لن تحتاج إلى كشف أي فئات
    /// مكوّن محددة لكود العميل، حتى أثناء تجميع شجرة الكائنات. الجانب
    /// السلبي هو أن هذه الطرق ستكون فارغة لمكوّنات مستوى الورقة.
    func add(component: Component)
    func remove(component: Component)

    /// يمكنك توفير طريقة تتيح لكود العميل معرفة ما إذا كان المكوّن
    /// يمكنه أن ينجب أبناء.
    func isComposite() -> Bool

    /// قد تُنفّذ فئة المكوّن الأساسية بعض السلوكيات الافتراضية أو تتركها
    /// للفئات المحددة.
    func operation() -> String
}

extension Component {

    func add(component: Component) {}
    func remove(component: Component) {}
    func isComposite() -> Bool {
        return false
    }
}

/// تمثّل فئة الورقة الكائنات الطرفية في التركيب. لا يمكن لورقة
/// أن تمتلك أي أبناء.
///
/// عادةً ما تقوم كائنات الورقة بالعمل الفعلي، في حين تفوّض كائنات
/// المركَّب فقط إلى مكوّناتها الفرعية.
class Leaf: Component {

    var parent: Component?

    func operation() -> String {
        return "Leaf"
    }
}

/// تمثّل فئة المركَّب المكوّنات المعقدة التي قد تمتلك أبناء. عادةً ما
/// تفوّض كائنات المركَّب العمل الفعلي لأبنائها ثم "تجمع" النتيجة.
class Composite: Component {

    var parent: Component?

    /// يحتوي هذا الحقل على الشجرة الفرعية للمكوّن.
    private var children = [Component]()

    /// يمكن لكائن المركَّب إضافة أو إزالة مكوّنات أخرى (بسيطة أو معقدة)
    /// من قائمة أبنائه.
    func add(component: Component) {
        var item = component
        item.parent = self
        children.append(item)
    }

    func remove(component: Component) {
        // ...
    }

    func isComposite() -> Bool {
        return true
    }

    /// يُنفّذ المركَّب منطقه الأساسي بطريقة معينة. يتجول بشكل متكرر عبر
    /// جميع أبنائه، جامعاً نتائجهم. وبما أن أبناء المركَّب يمررون هذه
    /// الاستدعاءات لأبنائهم وهكذا، فإن شجرة الكائنات بأكملها تُعبَر
    /// نتيجةً لذلك.
    func operation() -> String {
        let result = children.map({ $0.operation() })
        return "Branch(" + result.joined(separator: " ") + ")"
    }
}

class Client {

    /// يتعامل كود العميل مع جميع المكوّنات عبر الواجهة الأساسية.
    static func someClientCode(component: Component) {
        print("Result: " + component.operation())
    }

    /// بفضل كون عمليات إدارة الأبناء مُعلنة أيضاً في فئة المكوّن الأساسية،
    /// يمكن لكود العميل العمل مع كلٍّ من المكوّنات البسيطة والمعقدة.
    static func moreComplexClientCode(leftComponent: Component, rightComponent: Component) {
        if leftComponent.isComposite() {
            leftComponent.add(component: rightComponent)
        }
        print("Result: " + leftComponent.operation())
    }
}

/// لنرَ كيف يتلاءم كل شيء معاً.
class CompositeConceptual: XCTestCase {

    func testCompositeConceptual() {

        /// بهذه الطريقة يمكن لكود العميل دعم مكوّنات الورقة البسيطة...
        print("Client: I've got a simple component:")
        Client.someClientCode(component: Leaf())

        /// ...وكذلك المركّبات المعقدة.
        let tree = Composite()

        let branch1 = Composite()
        branch1.add(component: Leaf())
        branch1.add(component: Leaf())

        let branch2 = Composite()
        branch2.add(component: Leaf())
        branch2.add(component: Leaf())

        tree.add(component: branch1)
        tree.add(component: branch2)

        print("\nClient: Now I've got a composite tree:")
        Client.someClientCode(component: tree)

        print("\nClient: I don't need to check the components classes even when managing the tree:")
        Client.moreComplexClientCode(leftComponent: tree, rightComponent: Leaf())
    }
}

Client: I've got a simple component:
Result: Leaf

Client: Now I've got a composite tree:
Result: Branch(Branch(Leaf Leaf) Branch(Leaf Leaf))

Client: I don't need to check the components classes even when managing the tree:
Result: Branch(Branch(Leaf Leaf) Branch(Leaf Leaf) Leaf)

import UIKit
import XCTest

protocol Component {

    func accept<T: Theme>(theme: T)
}

extension Component where Self: UIViewController {

    func accept<T: Theme>(theme: T) {
        view.accept(theme: theme)
        view.subviews.forEach({ $0.accept(theme: theme) })
    }
}

extension UIView: Component {}
extension UIViewController: Component {}

extension Component where Self: UIView {

    func accept<T: Theme>(theme: T) {

        print("\t\(description): has applied \(theme.description)")

        backgroundColor = theme.backgroundColor
    }
}

extension Component where Self: UILabel {

    func accept<T: LabelTheme>(theme: T) {

        print("\t\(description): has applied \(theme.description)")

        backgroundColor = theme.backgroundColor
        textColor = theme.textColor
    }
}

extension Component where Self: UIButton {

    func accept<T: ButtonTheme>(theme: T) {

        print("\t\(description): has applied \(theme.description)")

        backgroundColor = theme.backgroundColor
        setTitleColor(theme.textColor, for: .normal)
        setTitleColor(theme.highlightedColor, for: .highlighted)
    }
}


protocol Theme: CustomStringConvertible {

    var backgroundColor: UIColor { get }
}

protocol ButtonTheme: Theme {

    var textColor: UIColor { get }

    var highlightedColor: UIColor { get }

    /// other properties
}

protocol LabelTheme: Theme {

    var textColor: UIColor { get }

    /// other properties
}

/// Button Themes

struct DefaultButtonTheme: ButtonTheme {

    var textColor = UIColor.red

    var highlightedColor = UIColor.white

    var backgroundColor = UIColor.orange

    var description: String { return "Default Buttom Theme" }
}

struct NightButtonTheme: ButtonTheme {

    var textColor = UIColor.white

    var highlightedColor = UIColor.red

    var backgroundColor = UIColor.black

    var description: String { return "Night Buttom Theme" }
}

/// Label Themes

struct DefaultLabelTheme: LabelTheme {

    var textColor = UIColor.red

    var backgroundColor = UIColor.black

    var description: String { return "Default Label Theme" }
}

struct NightLabelTheme: LabelTheme {

    var textColor = UIColor.white

    var backgroundColor = UIColor.black

    var description: String { return "Night Label Theme" }
}



class CompositeRealWorld: XCTestCase {

    func testCompositeRealWorld() {

        print("\nClient: Applying 'default' theme for 'UIButton'")
        apply(theme: DefaultButtonTheme(), for: UIButton())

        print("\nClient: Applying 'night' theme for 'UIButton'")
        apply(theme: NightButtonTheme(), for: UIButton())


        print("\nClient: Let's use View Controller as a composite!")

        /// Night theme
        print("\nClient: Applying 'night button' theme for 'WelcomeViewController'...")
        apply(theme: NightButtonTheme(), for: WelcomeViewController())
        print()

        print("\nClient: Applying 'night label' theme for 'WelcomeViewController'...")
        apply(theme: NightLabelTheme(), for: WelcomeViewController())
        print()

        /// Default Theme
        print("\nClient: Applying 'default button' theme for 'WelcomeViewController'...")
        apply(theme: DefaultButtonTheme(), for: WelcomeViewController())
        print()

        print("\nClient: Applying 'default label' theme for 'WelcomeViewController'...")
        apply(theme: DefaultLabelTheme(), for: WelcomeViewController())
        print()
    }

    func apply<T: Theme>(theme: T, for component: Component) {
        component.accept(theme: theme)
    }
}

class WelcomeViewController: UIViewController {

    class ContentView: UIView {

        var titleLabel = UILabel()
        var actionButton = UIButton()

        override init(frame: CGRect) {
            super.init(frame: frame)
            setup()
        }

        required init?(coder decoder: NSCoder) {
            super.init(coder: decoder)
            setup()
        }

        func setup() {
            addSubview(titleLabel)
            addSubview(actionButton)
        }
    }

    override func loadView() {
        view = ContentView()
    }
}

/// Let's override a description property for the better output

extension WelcomeViewController {

    open override var description: String { return "WelcomeViewController" }
}

extension WelcomeViewController.ContentView {

    override var description: String { return "ContentView" }
}

extension UIButton {

    open override var description: String { return "UIButton" }
}

extension UILabel {

    open override var description: String { return "UILabel" }
}

Client: Applying 'default' theme for 'UIButton'
UIButton: has applied Default Buttom Theme

Client: Applying 'night' theme for 'UIButton'
UIButton: has applied Night Buttom Theme

Client: Let's use View Controller as a composite!

Client: Applying 'night button' theme for 'WelcomeViewController'...
ContentView: has applied Night Buttom Theme
UILabel: has applied Night Buttom Theme
UIButton: has applied Night Buttom Theme
```

### typescript

```typescript
/**
 * تُعلن فئة المكوّن الأساسية عن العمليات المشتركة لكلٍّ من الكائنات
 * البسيطة والمعقدة في التركيب.
 */
abstract class Component {
    protected parent!: Component | null;

    /**
     * يمكن اختياريًا أن تُعلن فئة المكوّن الأساسية عن واجهة لضبط والوصول
     * لوالد المكوّن في هيكل شجري. يمكنها أيضاً توفير تنفيذ افتراضي لهذه الطرق.
     */
    public setParent(parent: Component | null) {
        this.parent = parent;
    }

    public getParent(): Component | null {
        return this.parent;
    }

    /**
     * في بعض الحالات، قد يكون من المفيد تعريف عمليات إدارة الأبناء مباشرةً
     * في فئة المكوّن الأساسية. بهذه الطريقة، لن تحتاج إلى كشف أي فئات
     * مكوّن محددة لكود العميل، حتى أثناء تجميع شجرة الكائنات. الجانب
     * السلبي هو أن هذه الطرق ستكون فارغة لمكوّنات مستوى الورقة.
     */
    public add(component: Component): void { }

    public remove(component: Component): void { }

    /**
     * يمكنك توفير طريقة تتيح لكود العميل معرفة ما إذا كان المكوّن
     * يمكنه أن ينجب أبناء.
     */
    public isComposite(): boolean {
        return false;
    }

    /**
     * قد تُنفّذ فئة المكوّن الأساسية بعض السلوكيات الافتراضية أو تتركها
     * للفئات المحددة (بتعريف الطريقة المحتوية للسلوك كـ"abstract").
     */
    public abstract operation(): string;
}

/**
 * تمثّل فئة الورقة الكائنات الطرفية في التركيب. لا يمكن لورقة
 * أن تمتلك أي أبناء.
 *
 * عادةً ما تقوم كائنات الورقة بالعمل الفعلي، في حين تفوّض كائنات
 * المركَّب فقط إلى مكوّناتها الفرعية.
 */
class Leaf extends Component {
    public operation(): string {
        return 'Leaf';
    }
}

/**
 * تمثّل فئة المركَّب المكوّنات المعقدة التي قد تمتلك أبناء. عادةً ما
 * تفوّض كائنات المركَّب العمل الفعلي لأبنائها ثم "تجمع" النتيجة.
 */
class Composite extends Component {
    protected children: Component[] = [];

    /**
     * يمكن لكائن المركَّب إضافة أو إزالة مكوّنات أخرى (بسيطة أو معقدة)
     * من قائمة أبنائه.
     */
    public add(component: Component): void {
        this.children.push(component);
        component.setParent(this);
    }

    public remove(component: Component): void {
        const componentIndex = this.children.indexOf(component);
        this.children.splice(componentIndex, 1);

        component.setParent(null);
    }

    public isComposite(): boolean {
        return true;
    }

    /**
     * يُنفّذ المركَّب منطقه الأساسي بطريقة معينة. يتجول بشكل متكرر عبر
     * جميع أبنائه، جامعاً نتائجهم. وبما أن أبناء المركَّب يمررون هذه
     * الاستدعاءات لأبنائهم وهكذا، فإن شجرة الكائنات بأكملها تُعبَر
     * نتيجةً لذلك.
     */
    public operation(): string {
        const results = [];
        for (const child of this.children) {
            results.push(child.operation());
        }

        return `Branch(${results.join('+')})`;
    }
}

/**
 * يتعامل كود العميل مع جميع المكوّنات عبر الواجهة الأساسية.
 */
function clientCode(component: Component) {
    // ...

    console.log(`RESULT: ${component.operation()}`);

    // ...
}

/**
 * بهذه الطريقة يمكن لكود العميل دعم مكوّنات الورقة البسيطة...
 */
const simple = new Leaf();
console.log('Client: I\'ve got a simple component:');
clientCode(simple);
console.log('');

/**
 * ...as well as the complex composites.
 */
const tree = new Composite();
const branch1 = new Composite();
branch1.add(new Leaf());
branch1.add(new Leaf());
const branch2 = new Composite();
branch2.add(new Leaf());
tree.add(branch1);
tree.add(branch2);
console.log('Client: Now I\'ve got a composite tree:');
clientCode(tree);
console.log('');

/**
 * بفضل كون عمليات إدارة الأبناء مُعلنة في فئة المكوّن الأساسية،
 * يمكن لكود العميل العمل مع أي مكوّن، بسيط أو معقد، دون الاعتماد
 * على فئاته المحددة.
 */
function clientCode2(component1: Component, component2: Component) {
    // ...

    if (component1.isComposite()) {
        component1.add(component2);
    }
    console.log(`RESULT: ${component1.operation()}`);

    // ...
}

console.log('Client: I don\'t need to check the components classes even when managing the tree:');
clientCode2(tree, simple);

Client: I've got a simple component:
RESULT: Leaf

Client: Now I've got a composite tree:
RESULT: Branch(Branch(Leaf+Leaf)+Branch(Leaf))

Client: I don't need to check the components classes even when managing the tree:
RESULT: Branch(Branch(Leaf+Leaf)+Branch(Leaf)+Leaf)
```

