Skip to content

Mediator

Hamed Ramzi edited this page May 30, 2022 · 5 revisions

الگوی طراحی Mediator

یکی از اصولی که در طراحی شئ گرا باید رعایت شود این است که: کلاس ها و اشیائی که از روی آنها ساخته می‌شوند، باید حداقل وابستگی را به یکدیگر داشته باشند. به این معنی که هرکدام بتوانند به شکل جداگانه کار خود را انجام بدهند و در صورت نیاز فارغ از این که هرکدام چگونه وظیفه خود را انجام می دهند با یکدیگر تعامل داشته باشند. این تعامل باید به گونه ای باشد که وقتی تغییری در یکی از کلاس ها اعمال شد، کلاسی که با کلاس تغییر داده شده همکاری می کند نیازمند تغییر نباشد. چنین اپلیکیشنی اصطلاحا Loosly Coupled هست و کامپوننت های اون کمترین وابستگی به هم رو دارند. یکی از الگوهایی که در رعایت این اصل بسیار تاثیر میگذاره، الگوی طراحی Mediator است.

الگوی Mediator یا میانجی یک الگوی طراحی رفتاری (Behavioral) است که به ما امکان می دهد** وابستگی های آشفته بین اشیا را کاهش دهیم**. این الگو ارتباطات مستقیم بین اشیا را محدود می کند و آنها را مجبور می کند که فقط از طریق یک شئ واسطه یا میانجی همکاری کنند.


مسئله

فرض کنید که برای ساخت و ویرایش پروفایل کاربران، یک دیالوگ داریم.. که شامل کنترل های مختلف فرم مانند تکست اینپوت ، چک باکس ، دکمه ها و غیره است.

با تکامل برنامه، رابطه المان های رابط کاربری پیچیده تر می‌شود با تکامل برنامه، رابطه المان های رابط کاربری پیچیده تر می‌شود

برخی از عناصر فرم ممکن است با بقیه تعامل داشته باشند. مثلا ممکنه با انتخاب یک چک باکس (مثلا "شاغل هستم")، یه تکست اینپوت جدید ظاهر بشه و داده جدیدی (عنوان شغل) رو بگیره.

روابط بین عناصر رشد می‌کند، پس تغییرات در برخی از عناصر ممکن است بر عناصر دیگر تأثیر بگذارد. روابط بین عناصر رشد می‌کند، پس تغییرات در برخی از عناصر ممکن است بر عناصر دیگر تأثیر بگذارد.

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

برای طراحی یک فرم دیگر، یا باید از تمام کلاس ها کنار هم استفاده کنید و یا از هیچ کدام استفاده نکنید.

راه حل

الگوی Mediator پیشنهاد می کند که شما تمام ارتباطات مستقیم را بین کلاس هایی که می خواهید مستقل از یکدیگر ایجاد کنید ، از بین ببرید... در عوض، این اجزا باید به طور غیر مستقیم و با فراخوانی یک شیء میانجی که تماس ها را به اجزای مناسب هدایت می کند، همکاری کنند. در نتیجه ، اجزاء به جای اینکه به ده ها تن از همکاران خود متکی باشند ، فقط به یک طبقه میانجی، وابستگی دارند.

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

مهمترین تغییر در عناصر اتفاق می افتد. بیایید دکمه ارسال را در نظر بگیریم. قبلاً ، هر بار که یک کاربر روی این دکمه کلیک می کرد، باید تمام مقادیر فرم اعتبار سنجی میشد. اما اکنون تنها وظیفه آن اطلاع رسانی به دیالوگ در مورد کلیک است. پس از دریافت این اعلان ، خود دیالوگ اعتبارسنجی ها را انجام می دهد یا کار را به عناصر دیگری منتقل می کند. بنابراین دکمه ارسال، به جای اینکه به تمام عناصر فرم گره خورده باشد، تنها به کلاس دیالوگ وابسته است.

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

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

در دنیای واقعی

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

برج مراقبت نیازی به کنترل کل پروسه پرواز ندارد; و دلیل وجودش اعمال محدودیت در حیطه ترمینال است.

ساختار

۱) کامپوننت ها کلاس های مختلفی هستند که بیزنس لاجیک (business logic) دارند. هر کامپوننت رفرنسی به یک میانجی دارد که از طریق اینترفیس میانجی اعمال شده است. این کامپوننت هیچ اطلاعی از کلاس اصلی میانجی ندارد... پس می توانید با پیوند دادن آن به یک میانجی متفاوت، از آن در برنامه های دیگر استفاده کنید.

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

۳) میانجی های ثابت (Concrete) روابط بین کامپوننت ها را کپسوله سازی می‌کنند. میانجی های ثابت اغلب رفرنسی را به تمام کامپوننت هایی که مدیریت میکنند، ذخیره می‌کنند. (در برخی موارد حتی رفرنس های چرخه حیات کامپوننت ها را هم ذخیره می‌کنند)

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

پس یک کامپوننت در نادانی مطلق به سر می‌برد.. فرستنده نمی داند چه کسی به درخواست خود رسیدگی می‌کند و گیرنده نمی‌داند که چه کسی در وهله اول درخواست را ارسال کرده است.

کاربردها

۱) مواقعی که تغییر برخی از کلاس ها دشوار است. (زیرا آنها به شدت با کلاس های دیگر گره خورده‌اند)

۲) زمانی که نتوانید از یک کامپوننت در برنامه دیگری استفاده کنید زیرا بیش از حد به کامپوننت های دیگر وابسته است.

۳) زمانی که تنها برای استفاده مجدد از برخی رفتارها، ساب-کلاس های زیادی می‌سازید.

مزایا و معایب

  • قاعده تک مسئولیتی (Single Responsibility Principle) رعایت می‌شود (می توانید ارتباطات بین اجزای مختلف را در یک مکان واحد استخراج کرده و درک و نگهداری آن را آسان تر کنید)
  • قاعده باز و بسته (Open/Closed Principle) رعایت می‌شود. (می ‌توانید میانجی های جدید را بدون نیاز به تغییر در کامپوننت ها معرفی کرد)
  • می ‌توانید در هم تنیدگی کامپوننت های مختلف یک برنامه را کاهش دهید.
  • می توانید به راحتی از کامپوننت های جداگانه، مجددا استفاده کنید.
  • با گذشت زمان، یک کلاس میانجی می تواند به یک God Object تبدیل شود.

رابطه الگوی Mediator با سایر الگوها

الگوی Mediator یک سری شباهت ها با الگوهای Chain of Responsibility, Command و Observer دارد.. در واقع این الگوها روشهای مختلف اتصال، بین فرستنده ها و گیرنده های درخواست را آدرس دهی می‌کنند.

الگوی Chain of Responsibility : یک درخواست را به طور متوالی از طریق یک زنجیره پویا از گیرنده های بالقوه منتقل می کند، تا زمانی که یکی از زنجیره ها به درخواست رسیدگی کند.

الگوی Command : برای برقراری ارتباطات یک طرفه بین فرستنده ها و گیرنده ها مورد استفاده قرار می‌گیرد.

و الگوی Observer : به گیرنده ها اجازه می دهد تا به صورت داینامیک در دریافت درخواست ها مشترک شوند و یا اشتراکشان را لغو کنند.

الگوهای Facade و Mediator وظایف یکسانی دارند. آنها سعی در سازماندهی همکاری بین کلاس های در هم تنیده را دارند.

فِساد (Facade) یک رابط ساده برای مجموعه ای از اشیا است، اما هیچ ویژگی جدیدی را معرفی نمی کند. و این در حالی است که خود سیستم از وجود فساد بی اطلاع است. بدین ترتیب اشیای درون سیستم می‌توانند مستقیما در ارتباط باشند میانجی (Mediator) ارتباط بین کامپوننت های سیستم را متمرکز می‌کند. کامپوننت ها تنها از وجود میانجی مطلع هستند و نمی‌توانند ارتباط مستقیم داشته باشند.

الگوهای Mediator و Observer تفاوتی نسبتا جزئی دارند و بعضی مواقع می‌توانید این ۲ گزینه را به جای هم تعبیه کنید.

هدف اصلی Mediator از بین بردن وابستگی های متقابل در میان مجموعه ای از کامپوننت های سیستم است. در عوض این کامپوننت ها می‌توانند به یک شئ میانی وابسته باشند. اما هدف اصلی Observer برقراری ارتباطات داینامیک یک طرفه میان اشیا ست. که ممکن است بعضی از این اشیا زیر مجموعه سایر اشیا باشند.

همچنین سبکی معروف از پیاده سازی الگوی Mediator وجود دارد که متکی به الگوی Observer است. در این حالت شئ میانی نقش یک ناشر را بازی می‌کند و کامپوننت ها نقش مشترکانی را دارند که رویدادهای شئ میانی را دنبال می‌کنند. پیاده سازی الگوی Mediator به این شکل بسیار به الگوی Observer شباهت دارد.

فراموش نکنید که الگوی Mediator به شکل های دیگری هم قابل پیاده سازی است. مثلا می‌توانید تمام کامپوننت ها رو به شکل دائمی به یک شئ میانی وصل کنید که در این حال شباهت ها با الگوی Observer کمتر و کمتر می‌شود.

حالا برنامه ای را تصور کنید که تمام کامپوننت های آن، تبدیل به ناشر شده باشند; و امکان ایجاد ارتباط داینامیک بین یکدیگر را فراهم کرده اند. در این حالت هیچ شئ میانی که مرکزی باشد، وجود ندارد; و تنها مجموعه ای توضیع شده از ناظر ها (Observers) وجود دارند.

مثال یک

components/Component.java

package design_patterns.mediator.example.components;

import design_patterns.mediator.example.mediator.Mediator;

/**
 * Common component interface.
 */
public interface Component {
    void setMediator(Mediator mediator);
    String getName();
}

components/AddButton.java

package design_patterns.mediator.example.components;

import design_patterns.mediator.example.mediator.Mediator;
import design_patterns.mediator.example.mediator.Note;

import javax.swing.*;
import java.awt.event.ActionEvent;

/**
 * Concrete components don't talk with each other. They have only one
 * communication channel–sending requests to the mediator.
 */
public class AddButton extends JButton implements Component {
    private Mediator mediator;

    public AddButton() {
        super("Add");
    }

    @Override
    public void setMediator(Mediator mediator) {
        this.mediator = mediator;
    }

    @Override
    protected void fireActionPerformed(ActionEvent actionEvent) {
        mediator.addNewNote(new Note());
    }

    @Override
    public String getName() {
        return "AddButton";
    }
}

components/DeleteButton.java

package design_patterns.mediator.example.components;

import design_patterns.mediator.example.mediator.Mediator;

import javax.swing.*;
import java.awt.event.ActionEvent;

/**
 * Concrete components don't talk with each other. They have only one
 * communication channel–sending requests to the mediator.
 */
public class DeleteButton extends JButton  implements Component {
    private Mediator mediator;

    public DeleteButton() {
        super("Del");
    }

    @Override
    public void setMediator(Mediator mediator) {
        this.mediator = mediator;
    }

    @Override
    protected void fireActionPerformed(ActionEvent actionEvent) {
        mediator.deleteNote();
    }

    @Override
    public String getName() {
        return "DelButton";
    }
}

components/Filter.java

package design_patterns.mediator.example.components;

import design_patterns.mediator.example.mediator.Mediator;
import design_patterns.mediator.example.mediator.Note;

import javax.swing.*;
import java.awt.event.KeyEvent;
import java.util.ArrayList;

/**
 * Concrete components don't talk with each other. They have only one
 * communication channel–sending requests to the mediator.
 */
public class Filter extends JTextField implements Component {
    private Mediator mediator;
    private ListModel listModel;

    public Filter() {}

    @Override
    public void setMediator(Mediator mediator) {
        this.mediator = mediator;
    }

    @Override
    protected void processComponentKeyEvent(KeyEvent keyEvent) {
        String start = getText();
        searchElements(start);
    }

    public void setList(ListModel listModel) {
        this.listModel = listModel;
    }

    private void searchElements(String s) {
        if (listModel == null) {
            return;
        }

        if (s.equals("")) {
            mediator.setElementsList(listModel);
            return;
        }

        ArrayList<Note> notes = new ArrayList<>();
        for (int i = 0; i < listModel.getSize(); i++) {
            notes.add((Note) listModel.getElementAt(i));
        }
        DefaultListModel<Note> listModel = new DefaultListModel<>();
        for (Note note : notes) {
            if (note.getName().contains(s)) {
                listModel.addElement(note);
            }
        }
        mediator.setElementsList(listModel);
    }

    @Override
    public String getName() {
        return "Filter";
    }
}

components/List.java

package design_patterns.mediator.example.components;

import design_patterns.mediator.example.mediator.Mediator;
import design_patterns.mediator.example.mediator.Note;

import javax.swing.*;

/**
 * Concrete components don't talk with each other. They have only one
 * communication channel–sending requests to the mediator.
 */
@SuppressWarnings("unchecked")
public class List extends JList implements Component {
    private Mediator mediator;
    private final DefaultListModel LIST_MODEL;

    public List(DefaultListModel listModel) {
        super(listModel);
        this.LIST_MODEL = listModel;
        setModel(listModel);
        this.setLayoutOrientation(JList.VERTICAL);
        Thread thread = new Thread(new Hide(this));
        thread.start();
    }

    @Override
    public void setMediator(Mediator mediator) {
        this.mediator = mediator;
    }

    public void addElement(Note note) {
        LIST_MODEL.addElement(note);
        int index = LIST_MODEL.size() - 1;
        setSelectedIndex(index);
        ensureIndexIsVisible(index);
        mediator.sendToFilter(LIST_MODEL);
    }

    public void deleteElement() {
        int index = this.getSelectedIndex();
        try {
            LIST_MODEL.remove(index);
            mediator.sendToFilter(LIST_MODEL);
        } catch (ArrayIndexOutOfBoundsException ignored) {}
    }

    public Note getCurrentElement() {
        return (Note)getSelectedValue();
    }

    @Override
    public String getName() {
        return "List";
    }

    private class Hide implements Runnable {
        private List list;

        Hide(List list) {
            this.list = list;
        }

        @Override
        public void run() {
            while (true) {
                try {
                    Thread.sleep(300);
                } catch (InterruptedException ex) {
                    ex.printStackTrace();
                }
                if (list.isSelectionEmpty()) {
                    mediator.hideElements(true);
                } else {
                    mediator.hideElements(false);
                }
            }
        }
    }
}

components/SaveButton.java

package design_patterns.mediator.example.components;

import design_patterns.mediator.example.mediator.Mediator;

import javax.swing.*;
import java.awt.event.ActionEvent;

/**
 * Concrete components don't talk with each other. They have only one
 * communication channel–sending requests to the mediator.
 */
public class SaveButton extends JButton implements Component {
    private Mediator mediator;

    public SaveButton() {
        super("Save");
    }

    @Override
    public void setMediator(Mediator mediator) {
        this.mediator = mediator;
    }

    @Override
    protected void fireActionPerformed(ActionEvent actionEvent) {
        mediator.saveChanges();
    }

    @Override
    public String getName() {
        return "SaveButton";
    }
}

components/TextBox.java

package design_patterns.mediator.example.components;

import design_patterns.mediator.example.mediator.Mediator;

import javax.swing.*;
import java.awt.event.KeyEvent;

/**
 * Concrete components don't talk with each other. They have only one
 * communication channel–sending requests to the mediator.
 */
public class TextBox extends JTextArea implements Component {
    private Mediator mediator;

    @Override
    public void setMediator(Mediator mediator) {
        this.mediator = mediator;
    }

    @Override
    protected void processComponentKeyEvent(KeyEvent keyEvent) {
        mediator.markNote();
    }

    @Override
    public String getName() {
        return "TextBox";
    }
}

components/Title.java

package design_patterns.mediator.example.components;

import design_patterns.mediator.example.mediator.Mediator;

import javax.swing.*;
import java.awt.event.KeyEvent;

/**
 * Concrete components don't talk with each other. They have only one
 * communication channel–sending requests to the mediator.
 */
public class Title extends JTextField implements Component {
    private Mediator mediator;

    @Override
    public void setMediator(Mediator mediator) {
        this.mediator = mediator;
    }

    @Override
    protected void processComponentKeyEvent(KeyEvent keyEvent) {
        mediator.markNote();
    }

    @Override
    public String getName() {
        return "Title";
    }
}

mediator/Mediator.java: Defines common mediator interface

package design_patterns.mediator.example.mediator;

import design_patterns.mediator.example.components.Component;

import javax.swing.*;

/**
 * Common mediator interface.
 */
public interface Mediator {
    void addNewNote(Note note);
    void deleteNote();
    void getInfoFromList(Note note);
    void saveChanges();
    void markNote();
    void clear();
    void sendToFilter(ListModel listModel);
    void setElementsList(ListModel list);
    void registerComponent(Component component);
    void hideElements(boolean flag);
    void createGUI();
}

mediator/Editor.java: Concrete mediator

package design_patterns.mediator.example.mediator;

import design_patterns.mediator.example.components.*;
import design_patterns.mediator.example.components.Component;
import design_patterns.mediator.example.components.List;

import javax.swing.*;
import javax.swing.border.LineBorder;
import java.awt.*;

/**
 * Concrete mediator. All chaotic communications between concrete components
 * have been extracted to the mediator. Now components only talk with the
 * mediator, which knows who has to handle a request.
 */
public class Editor implements Mediator {
    private Title title;
    private TextBox textBox;
    private AddButton add;
    private DeleteButton del;
    private SaveButton save;
    private List list;
    private Filter filter;

    private JLabel titleLabel = new JLabel("Title:");
    private JLabel textLabel = new JLabel("Text:");
    private JLabel label = new JLabel("Add or select existing note to proceed...");
  
    /**
     * Here the registration of components by the mediator.
     */
    @Override
    public void registerComponent(Component component) {
        component.setMediator(this);
        switch (component.getName()) {
            case "AddButton":
                add = (AddButton)component;
                break;
            case "DelButton":
                del = (DeleteButton)component;
                break;
            case "Filter":
                filter = (Filter)component;
                break;
            case "List":
                list = (List)component;
                this.list.addListSelectionListener(listSelectionEvent -> {
                    Note note = (Note)list.getSelectedValue();
                    if (note != null) {
                        getInfoFromList(note);
                    } else {
                        clear();
                    }
                });
                break;
            case "SaveButton":
                save = (SaveButton)component;
                break;
            case "TextBox":
                textBox = (TextBox)component;
                break;
            case "Title":
                title = (Title)component;
                break;
        }
    }

    /**
     * Various methods to handle requests from particular components.
     */
    @Override
    public void addNewNote(Note note) {
        title.setText("");
        textBox.setText("");
        list.addElement(note);
    }

    @Override
    public void deleteNote() {
        list.deleteElement();
    }

    @Override
    public void getInfoFromList(Note note) {
        title.setText(note.getName().replace('*', ' '));
        textBox.setText(note.getText());
    }

    @Override
    public void saveChanges() {
        try {
            Note note = (Note) list.getSelectedValue();
            note.setName(title.getText());
            note.setText(textBox.getText());
            list.repaint();
        } catch (NullPointerException ignored) {}
    }

    @Override
    public void markNote() {
        try {
            Note note = list.getCurrentElement();
            String name = note.getName();
            if (!name.endsWith("*")) {
                note.setName(note.getName() + "*");
            }
            list.repaint();
        } catch (NullPointerException ignored) {}
    }

    @Override
    public void clear() {
        title.setText("");
        textBox.setText("");
    }

    @Override
    public void sendToFilter(ListModel listModel) {
        filter.setList(listModel);
    }

    @SuppressWarnings("unchecked")
    @Override
    public void setElementsList(ListModel list) {
        this.list.setModel(list);
        this.list.repaint();
    }

    @Override
    public void hideElements(boolean flag) {
        titleLabel.setVisible(!flag);
        textLabel.setVisible(!flag);
        title.setVisible(!flag);
        textBox.setVisible(!flag);
        save.setVisible(!flag);
        label.setVisible(flag);
    }

    @Override
    public void createGUI() {
        JFrame notes = new JFrame("Notes");
        notes.setSize(960, 600);
        notes.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        JPanel left = new JPanel();
        left.setBorder(new LineBorder(Color.BLACK));
        left.setSize(320, 600);
        left.setLayout(new BoxLayout(left, BoxLayout.Y_AXIS));
        JPanel filterPanel = new JPanel();
        filterPanel.add(new JLabel("Filter:"));
        filter.setColumns(20);
        filterPanel.add(filter);
        filterPanel.setPreferredSize(new Dimension(280, 40));
        JPanel listPanel = new JPanel();
        list.setFixedCellWidth(260);
        listPanel.setSize(320, 470);
        JScrollPane scrollPane = new JScrollPane(list);
        scrollPane.setPreferredSize(new Dimension(275, 410));
        listPanel.add(scrollPane);
        JPanel buttonPanel = new JPanel();
        add.setPreferredSize(new Dimension(85, 25));
        buttonPanel.add(add);
        del.setPreferredSize(new Dimension(85, 25));
        buttonPanel.add(del);
        buttonPanel.setLayout(new FlowLayout());
        left.add(filterPanel);
        left.add(listPanel);
        left.add(buttonPanel);
        JPanel right = new JPanel();
        right.setLayout(null);
        right.setSize(640, 600);
        right.setLocation(320, 0);
        right.setBorder(new LineBorder(Color.BLACK));
        titleLabel.setBounds(20, 4, 50, 20);
        title.setBounds(60, 5, 555, 20);
        textLabel.setBounds(20, 4, 50, 130);
        textBox.setBorder(new LineBorder(Color.DARK_GRAY));
        textBox.setBounds(20, 80, 595, 410);
        save.setBounds(270, 535, 80, 25);
        label.setFont(new Font("Verdana", Font.PLAIN, 22));
        label.setBounds(100, 240, 500, 100);
        right.add(label);
        right.add(titleLabel);
        right.add(title);
        right.add(textLabel);
        right.add(textBox);
        right.add(save);
        notes.setLayout(null);
        notes.getContentPane().add(left);
        notes.getContentPane().add(right);
        notes.setResizable(false);
        notes.setLocationRelativeTo(null);
        notes.setVisible(true);
    }
}

mediator/Note.java: A note’s class

package design_patterns.mediator.example.mediator;

/**
 * Note class.
 */
public class Note {
    private String name;
    private String text;

    public Note() {
        name = "New note";
    }

    public void setName(String name) {
        this.name = name;
    }

    public void setText(String text) {
        this.text = text;
    }

    public String getName() {
        return name;
    }

    public String getText() {
        return text;
    }

    @Override
    public String toString() {
        return name;
    }
}

Demo.java: Initialization code

package design_patterns.mediator.example;

import design_patterns.mediator.example.components.*;
import design_patterns.mediator.example.mediator.Editor;
import design_patterns.mediator.example.mediator.Mediator;

import javax.swing.*;

/**
 * Demo class. Everything comes together here.
 */
public class Demo {
    public static void main(String[] args) {
        Mediator mediator = new Editor();

        mediator.registerComponent(new Title());
        mediator.registerComponent(new TextBox());
        mediator.registerComponent(new AddButton());
        mediator.registerComponent(new DeleteButton());
        mediator.registerComponent(new SaveButton());
        mediator.registerComponent(new List(new DefaultListModel()));
        mediator.registerComponent(new Filter());

        mediator.createGUI();
    }
}

OutputDemo.png: Execution result

مثال 2

#### main.py: Conceptual example
from __future__ import annotations
from abc import ABC


class Mediator(ABC):
    """
    The Mediator interface declares a method used by components to notify the
    mediator about various events. The Mediator may react to these events and
    pass the execution to other components.
    """

    def notify(self, sender: object, event: str) -> None:
        pass


class ConcreteMediator(Mediator):
    def __init__(self, component1: Component1, component2: Component2) -> None:
        self._component1 = component1
        self._component1.mediator = self
        self._component2 = component2
        self._component2.mediator = self

    def notify(self, sender: object, event: str) -> None:
        if event == "A":
            print("Mediator reacts on A and triggers following operations:")
            self._component2.do_c()
        elif event == "D":
            print("Mediator reacts on D and triggers following operations:")
            self._component1.do_b()
            self._component2.do_c()


class BaseComponent:
    """
    The Base Component provides the basic functionality of storing a mediator's
    instance inside component objects.
    """

    def __init__(self, mediator: Mediator = None) -> None:
        self._mediator = mediator

    @property
    def mediator(self) -> Mediator:
        return self._mediator

    @mediator.setter
    def mediator(self, mediator: Mediator) -> None:
        self._mediator = mediator


"""
Concrete Components implement various functionality. They don't depend on other
components. They also don't depend on any concrete mediator classes.
"""


class Component1(BaseComponent):
    def do_a(self) -> None:
        print("Component 1 does A.")
        self.mediator.notify(self, "A")

    def do_b(self) -> None:
        print("Component 1 does B.")
        self.mediator.notify(self, "B")


class Component2(BaseComponent):
    def do_c(self) -> None:
        print("Component 2 does C.")
        self.mediator.notify(self, "C")

    def do_d(self) -> None:
        print("Component 2 does D.")
        self.mediator.notify(self, "D")


if __name__ == "__main__":
    # The client code.
    c1 = Component1()
    c2 = Component2()
    mediator = ConcreteMediator(c1, c2)

    print("Client triggers operation A.")
    c1.do_a()

    print("\n", end="")

    print("Client triggers operation D.")
    c2.do_d()

Output.txt: Execution result

Client triggers operation A.
Component 1 does A.
Mediator reacts on A and triggers following operations:
Component 2 does C.


Client triggers operation D.
Component 2 does D.
Mediator reacts on D and triggers following operations:
Component 1 does B.
Component 2 does C.

مثال ۳

#### index.ts: Conceptual example
/**
 * The Mediator interface declares a method used by components to notify the
 * mediator about various events. The Mediator may react to these events and
 * pass the execution to other components.
 */
interface Mediator {
    notify(sender: object, event: string): void;
}

/**
 * Concrete Mediators implement cooperative behavior by coordinating several
 * components.
 */
class ConcreteMediator implements Mediator {
    private component1: Component1;

    private component2: Component2;

    constructor(c1: Component1, c2: Component2) {
        this.component1 = c1;
        this.component1.setMediator(this);
        this.component2 = c2;
        this.component2.setMediator(this);
    }

    public notify(sender: object, event: string): void {
        if (event === 'A') {
            console.log('Mediator reacts on A and triggers following operations:');
            this.component2.doC();
        }

        if (event === 'D') {
            console.log('Mediator reacts on D and triggers following operations:');
            this.component1.doB();
            this.component2.doC();
        }
    }
}

/**
 * The Base Component provides the basic functionality of storing a mediator's
 * instance inside component objects.
 */
class BaseComponent {
    protected mediator: Mediator;

    constructor(mediator: Mediator = null) {
        this.mediator = mediator;
    }

    public setMediator(mediator: Mediator): void {
        this.mediator = mediator;
    }
}

/**
 * Concrete Components implement various functionality. They don't depend on
 * other components. They also don't depend on any concrete mediator classes.
 */
class Component1 extends BaseComponent {
    public doA(): void {
        console.log('Component 1 does A.');
        this.mediator.notify(this, 'A');
    }

    public doB(): void {
        console.log('Component 1 does B.');
        this.mediator.notify(this, 'B');
    }
}

class Component2 extends BaseComponent {
    public doC(): void {
        console.log('Component 2 does C.');
        this.mediator.notify(this, 'C');
    }

    public doD(): void {
        console.log('Component 2 does D.');
        this.mediator.notify(this, 'D');
    }
}

/**
 * The client code.
 */
const c1 = new Component1();
const c2 = new Component2();
const mediator = new ConcreteMediator(c1, c2);

console.log('Client triggers operation A.');
c1.doA();

console.log('');
console.log('Client triggers operation D.');
c2.doD();

Output.txt: Execution result

Client triggers operation A.
Component 1 does A.
Mediator reacts on A and triggers following operations:
Component 2 does C.

Client triggers operation D.
Component 2 does D.
Mediator reacts on D and triggers following operations:
Component 1 does B.
Component 2 does C.

منبع

https://virgool.io/@ali.bayat/%D8%A7%D9%84%DA%AF%D9%88%DB%8C-%D8%B7%D8%B1%D8%A7%D8%AD%DB%8C-mediator-co4gf3n9s3hw

Is necessary

Design Pattern

Creational

Structural

Behavioral

Template

Clone this wiki locally