زمان تخمینی مطالعه: 11 دقیقه

الگوی Composite یک الگوی طراحی ساختاری(Structural) است که به شما امکان می‌دهد اشیاء را در ساختارهای درخت مانند ترکیب کنید تا با این ساختار سلسله مراتب ایجاد شده را که بخشی از کل است را نشان دهید. این الگو به مشتریان اجازه می‌دهد تا با اشیا و ترکیبات اشیاء به طور یکنواخت رفتار کنند. به عبارت دیگر، چه با یک شیء منفرد و چه با گروهی از اشیا (کامپوزیت)، مشتریان می‌توانند به جای یکدیگر از آنها استفاده کنند. در واقع با این الگو می‌توان پس از ایجاد سلسله مراتب، با این ساختارها طوری کار کرد که گویی اشیاء منفرد هستند.

Composite design pattern

بیان مسئله: استفاده از الگوی ترکیبی (Composite) تنها زمانی معنا دارد که مدل اصلی برنامه شما را بتوان به صورت درختی نشان داد. به عنوان مثال، تصور کنید که دو نوع شی Products و Boxes را دارید. در این جالت یک Boxes می‌تواند حاوی چندین Products و همچنین تعدادی Boxesکوچکتر باشد. این Boxes های کوچک هم می‌توانند برخی از Products یا حتی Boxes های کوچکتر و غیره را نیز در خود جای دهند.

فرض کنید تصمیم دارید یک سیستم سفارش ایجاد کنید که از این کلاس‌ها استفاده کند. سفارش‌ها می‌توانند شامل محصولات ساده و بدون بسته‌بندی، و همچنین جعبه‌های پر از محصولات و جعبه‌های دیگر باشند. چگونه قیمت کل چنین سفارشی را تعیین می‌کنید؟

Structure of a complex order
یک سفارش ممکن است شامل محصولات مختلف بسته‌بندی شده در جعبه و بسته‌بندی شده در جعبه‌های بزرگتر و غیره باشد. کل ساختار شبیه یک درخت وارونه است.

برای حل این مشکل می‌توانید روش مستقیم را امتحان کنید و تمام جعبه‌ها را باز کنید، همه محصولات را مرور کنید و سپس هزینه کل را محاسبه کنید. این در دنیای واقعی قابل انجام است. اما در یک برنامه، به سادگی اجرای یک حلقه نیست. شما باید کلاس‌های Products و Boxes که می‌گذرید، سطح تودرتو جعبه‌ها و سایر جزئیات دیگر را بدانید. همه اینها باعث می‌شود که رویکرد مستقیم یا بیش از حد ناخوشایند یا حتی غیرممکن باشد.

الگوی Composite پیشنهاد می‌کند که از طریق یک اینترفیس مشترک با Productsو Boxes کار کنید که روشی را برای محاسبه قیمت کل تعریف می‌کند. خوب بیایید ببینیم این روش چگونه کار خواهد کرد؟ این الگو برای یک محصول، به سادگی قیمت محصول را برمی‌گرداند. برای یک جعبه، روی هر موردی که در جعبه وجود دارد می‌رود، قیمت آن را می‌پرسد و سپس کل این جعبه را برمی‌گرداند. اگر یکی از این اقلام یک جعبه کوچکتر بود، آن جعبه نیز شروع به مرور محتویات آن کرده و به همین ترتیب تا زمانی که قیمت تمام اجزای داخلی محاسبه شود. در این روش حتی یک جعبه می‌تواند مقداری هزینه اضافی مانند هزینه بسته‌بندی به قیمت نهایی اضافه کند.

Solution suggested by the Composite pattern
الگوی Composite به کاربر امکان می‌دهد یک رفتار را به صورت بازگشتی روی تمام اجزای یک درخت شی اجرا کنید.

بزرگترین مزیت این رویکرد این است که نیازی نیست به کلاس‌های مشخصی از اشیاء که درخت را تشکیل می‌دهند اهمیت دهید. دانستن این که آیا یک شی یک محصول ساده است یا یک جعبه پیچیده لازم نیست. می‌توانید از طریق اینترفیس مشترک با همه آنها یکسان رفتار کنید. همچنین زمانی که یک متد را فراخوانی می‌کنید، خود اشیا درخواست را به درخت ارسال می‌کنند.

نمونه قابل قیاس در دنیای واقعی

ارتش اکثر کشورها به صورت سلسله مراتبی ساختار یافته‌اند. یک ارتش از چندین بخش تشکیل شده است. یک لشکر مجموعه‌ای از تیپ‌ها است و یک تیپ شامل جوخه‌هایی است که می‌توانند به دسته‌ها تقسیم شوند. در نهایت، یک دسته یک گروه کوچک از سربازان واقعی است. دستورات در بالای سلسله مراتب صادر می‌شود و به هر سطح منتقل می‌شود تا زمانی که هر سرباز بداند چه کاری باید انجام شود.

An example of a military structure
نمونه‌ای از ساختار نظامی و ارتشی.

ساختار الگوی Composition

در این بخش به بررسی ساختار الگوی ترکیبی(Composition) می‌پردازیم و پیاده‌سازی آن را به صورت UML خواهیم دید. 

شبه کد(Pseudocode)

در این مثال، الگوی Composite به شما امکان می‌دهد انباشته کردن اشکال هندسی را در یک ویرایشگر گرافیکی پیاده‌سازی کنید.

Structure of the Composite example
مثال ویرایشگر اشکال هندسی.

کلاس CompoundGraphic کانتینری است که می‌تواند شامل هر تعداد زیرشکل از جمله اشکال ترکیبی دیگر باشد. یک شکل مرکب همان متد‌های یک شکل ساده را دارد. با این حال، به جای اینکه کاری را به تنهایی انجام دهد، یک شکل مرکب درخواست را به صورت بازگشتی به همه فرزندان خود ارسال می‌کند و نتیجه را «خلاصه» می‌کند. کد کلاینت با همه اشکال از طریق اینترفیس واحد مشترک برای همه کلاس‌های شکل کار می‌کند. بنابراین، مشتری نمی‌داند که آیا با یک شکل ساده کار می‌کند یا یک شکل مرکب. مشتری می‌تواند با ساختارهای شی بسیار پیچیده کار کند، بدون اینکه به کلاس‌های concrete که آن ساختار را تشکیل می‌دهند، وابسته شود.

// The component interface declares common operations for both
// simple and complex objects of a composition.
interface Graphic is
    method move(x, y)
    method draw()

// The leaf class represents end objects of a composition. A
// leaf object can't have any sub-objects. Usually, it's leaf
// objects that do the actual work, while composite objects only
// delegate to their sub-components.
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
        // Draw a dot at X and Y.

// All component classes can extend other components.
class Circle extends Dot is
    field radius

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

    method draw() is
        // Draw a circle at X and Y with radius R.

// The composite class represents complex components that may
// have children. Composite objects usually delegate the actual
// work to their children and then "sum up" the result.
class CompoundGraphic implements Graphic is
    field children: array of Graphic

    // A composite object can add or remove other components
    // (both simple or complex) to or from its child list.
    method add(child: Graphic) is
        // Add a child to the array of children.

    method remove(child: Graphic) is
        // Remove a child from the array of children.

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

    // A composite executes its primary logic in a particular
    // way. It traverses recursively through all its children,
    // collecting and summing up their results. Since the
    // composite's children pass these calls to their own
    // children and so forth, the whole object tree is traversed
    // as a result.
    method draw() is
        // 1. For each child component:
        //     - Draw the component.
        //     - Update the bounding rectangle.
        // 2. Draw a dashed rectangle using the bounding
        // coordinates.


// The client code works with all the components via their base
// interface. This way the client code can support simple leaf
// components as well as complex composites.
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))
        // ...

    // Combine selected components into one complex composite
    // component.
    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 components will be drawn.
        all.draw()

قابلیت‌ها و کاربرد‌ها

نحوه پیاده‌سازی

  1. مطمئن شوید که مدل اصلی برنامه شما می‌تواند به عنوان یک ساختار درختی نمایش داده شود. سعی کنید آن را به عناصر و کانتینرها ساده تقسیم کنید. به یاد داشته باشید که کانتینرها باید بتوانند هم عناصر ساده و هم سایر کانتینرها را در خود داشته باشند.
  2. اینترفیس کامپوننت را با لیستی از متدهایی که برای اجزای ساده و پیچیده منطقی هستند، تعریف کنید.
  3. یک کلاس برگ برای نمایش عناصر ساده ایجاد کنید. یک برنامه ممکن است چندین کلاس برگ مختلف داشته باشد.
  4. یک کلاس کانتینر برای نمایش عناصر پیچیده ایجاد کنید. در این کلاس، یک فیلد آرایه برای ذخیره ارجاعات به عناصر فرعی قرار دهید. آرایه باید هم برگ و هم کانتینر را ذخیره کند، بنابراین مطمئن شوید که با نوع اینترفیس کامپوننت تعریف شده است. هنگام پیاده‌سازی متدهای اینترفیس کامپوننت، به یاد داشته باشید که یک کانتینر قرار است بیشتر کار را به عناصر فرعی واگذار کند.
  5. در نهایت متدهای افزودن و حذف عناصر فرزند در کانتینر را تعریف کنید. به خاطر داشته باشید که این عملیات را می‌توان در اینترفیس کامپوننت تعریف کرد. این امر اصل جداسازی اینترفیس را نقض می‌کند زیرا متدها در کلاس برگ خالی خواهند بود. با این حال، مشتری قادر خواهد بود با همه عناصر به طور مساوی رفتار کند، حتی در هنگام ترکیب درخت.

مزایا و معایب الگوی Composite

این الگوی طراحی دارای مزایا و معایبی به شرح زیر است:

– مزایا

– معایب

ارتباط با الگوهای دیگر

نمونه کد الگوی Composite

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *