Design Patterns

Last Updated: 10/3/2024

Mediator

  • Defines an object that encapsulates how a set of objects interact. Mediator promotes loose coupling by keeping objects from referring to each other explicitly, and it lets you vary their interaction independently.

Classical Structure

Mediator Classical Structure

Scenario

  • Build a dialog box/form for editing articles using GUI classes from some framework TextBox, ListBox, Button.
  • When you select article in listbox, textbox should be populated with the title of article and save button should be enabled.
  • When textbox is cleared the button should be disabled
  • When button is clicked, the text should be fetched

Problem

  • UI controls need to collaborate
  • You can't change the source code of UI controls based on form/dialog

Solution

  • ConcreteColleagues doesn't know about each other. They talk to each other via mediator
  • Coupling between ConcreteMediator and ConcreteColleague
internal abstract class DialogBox
{
   public abstract void Changed(UIControl control);
}
internal class UIControl
{
    protected readonly DialogBox owner;

    public UIControl(DialogBox owner)
    {
        this.owner = owner;
    }
}
internal class TextBox : UIControl
{
    private string content;

    public TextBox(DialogBox owner) : base(owner)
    {
    }

    public string Content
    {
        get => content;
        set
        {
            content = value;
            owner.Changed(this);
        }
    }
}
internal class ListBox : UIControl
{
    private string selection;

    public ListBox(DialogBox owner) : base(owner)
    {
    }

    public string Selection
    {
        get => selection;
        set
        {
            selection = value;
            owner.Changed(this);
        }
    }
}
internal class Button : UIControl
{
    bool isEnabled;

    public Button(DialogBox owner) : base(owner)
    {
    }

    public bool IsEnabled { 
        get => isEnabled;
        set { 
            isEnabled = value;
            owner.Changed(this);
        }
    }
}
internal class ArticleDialogBox : DialogBox
{
    private ListBox articlesListBox;
    private TextBox titleTextBox;
    private Button saveButton;

    public ArticleDialogBox()
    {
        articlesListBox =  new ListBox(this);
        titleTextBox = new TextBox(this);
        saveButton = new Button(this);
    }

    public void SimulateUserInteraction()
    {
        articlesListBox.Selection = "Article1";
        //titleTextBox.Content = "";
        Console.WriteLine(titleTextBox.Content);
        Console.WriteLine(saveButton.IsEnabled);

    }

    public override void Changed(UIControl control)
    {
        if (control == articlesListBox)
            articleSelected();
        else if(control == titleTextBox)
            titleChanged();
    }

    private void articleSelected()
    {
        titleTextBox.Content = articlesListBox.Selection;
        saveButton.IsEnabled = true;
    }

    private void titleChanged()
    {
        var content = titleTextBox.Content;
        saveButton.IsEnabled = !String.IsNullOrEmpty(content);
    }
}
public class Program
{
    static void Main(string[] args)
    {
	    var articleDialogBox = new ArticleDialogBox();
		articleDialogBox.SimulateUserInteraction();
	}
}

Example Structure

Mediator Example Structure

Example Code

Mediator Using Observer

Mediator Example Structure Using Observer

Example Code

internal abstract class UIControl
{
    List<Action> eventHandlers = new List<Action>();

    public void AddEventHandler(Action eventHandler)
    {
        eventHandlers.Add(eventHandler);
    }

    protected void NotifyEventHandlers()
    {
        foreach (Action handler in eventHandlers)
        {
            handler.Invoke();
        }
    }
}
internal class TextBox : UIControl
{
    private string content;

    public string Content
    {
        get => content;
        set
        {
            content = value;
            NotifyEventHandlers();
        }
    }
}
internal class ListBox : UIControl
{
    private string selection;

    public string Selection
    {
        get => selection;
        set
        {
            selection = value;
            NotifyEventHandlers();
        }
    }
}
internal class Button : UIControl
{
    bool isEnabled;

    public bool IsEnabled
    {
        get => isEnabled;
        set
        {
            isEnabled = value;
            NotifyEventHandlers();
        }
    }
}
internal class ArticleDialogBox
{
    private ListBox articlesListBox;
    private TextBox titleTextBox;
    private Button saveButton;

    public ArticleDialogBox()
    {
        articlesListBox = new ListBox();
        articlesListBox.AddEventHandler(ArticleSelected);

        titleTextBox = new TextBox();
        titleTextBox.AddEventHandler(TitleChanged);

        saveButton = new Button();
    }

    public void SimulateUserInteraction()
    {
        articlesListBox.Selection = "Article1";
        titleTextBox.Content = "";
        Console.WriteLine(titleTextBox.Content);
        Console.WriteLine(saveButton.IsEnabled);

    }

    private void ArticleSelected()
    {
        titleTextBox.Content = articlesListBox.Selection;
        saveButton.IsEnabled = true;
    }

    private void TitleChanged()
    {
        var content = titleTextBox.Content;
        saveButton.IsEnabled = !String.IsNullOrEmpty(content);
    }
}
public class Program
{
    static void Main(string[] args)
    {
	    var articleDialogBox = new ArticleDialogBox();
		articleDialogBox.SimulateUserInteraction();
	}
}