Közvetítő programtervezési minta
A programtervezésben a mediátor minta egy olyan objektum, mely megszabja, miképp viselkedjen objektumok egy csoportja. Ezt a mintát a viselkedési minták közé soroljuk annak köszönhetően, hogy képes megváltoztatni a program futási viselkedését.
Általában egy program nagyszámú csoportot tartalmaz, a logika és a számítás ezek között az osztályok között oszlik meg. Azonban ahogy újabb és újabb osztályokat készítünk egy programhoz, főleg karbantartás vagy refactoring közben, sokkal összetettebbé válhat a kommunikáció ezen osztályok között. A program ezáltal nehezen olvashatóvá és kezelhetővé válik. Továbbá nehezebb lesz megváltoztatni a programot, mivel bármilyen változás további osztályok kódjának megváltoztatását eredményezheti.
A Mediátor minta alkalmazásakor az objektumok közötti kommunikációt mediátor objektum végzi. Az objektumok ezentúl nem közvetlenül egymással kommunikálnak, hanem a Mediátoron keresztül. Ez csökkenti a kommunikáló objektumok közötti függőséget, ezáltal csökkenti a csatolás mértékét.
Definíció
szerkesztésA Mediátor minta biztosit számunkra egy objektumot, mely meghatározza, hogy objektumok egy csoportja hogyan hasson egymásra. Azáltal segíti a laza csatolást, hogy megelőzi, hogy az objektumok egymásra közvetlenül hivatkozzanak, így egymástól függetlenül változhat a hatásuk. A kliens osztály a mediátoron keresztül küldhet üzenetet a többi kliensnek, illetve a mediátor osztály egy eseményén keresztül kaphat üzenetet a többi klienstől.
A résztvevők
szerkesztésMediator - meghatározza az interfészt melyen keresztül a Colleague objektumok kommunikálhatnak egymással
ConcreteMediator - implementálja a mediátor interfészt és koordinálja a Colleague objektumok közötti kommunikációt. Ismeri az összes Colleague-et és kommunikációs céljaikat.
ConcreteColleague - más Colleague objektumokkal kommunikál a Mediátoron keresztül.
Példa
szerkesztésC#
szerkesztésA Mediátor minta elősegíti a laza csatolást, megelőzi, hogy az objektumok egymást közvetlenül hívják, ehelyett inkább használjanak egy különálló Mediátor implementációt, mely elvégzi ezt a feladatot. Alább láthatjuk amint a Mediátor regisztrálja a résztvevőket majd meghívja a függvényét, amikor szükséges.
//IVSR: Mediátor minta
public interface IComponent
{
void SetState(object state);
}
public class Component1 : IComponent
{
#region IComponent Members
public void SetState(object state)
{
//Nem teszünk semmit.
throw new NotImplementedException();
}
#endregion
}
public class Component2 : IComponent
{
#region IComponent Members
public void SetState(object state)
{
//Nem teszünk semmit
throw new NotImplementedException();
}
#endregion
}
// Közvetíti a feladatokat
public class Mediator
{
public IComponent Component1
{
get;
set;
}
public IComponent Component2
{
get;
set;
}
public void ChangeState(object state)
{
this.Component1.SetState(state);
this.Component2.SetState(state);
}
}
A Mediátor mintát használhatja egy chat szoba is, vagy egy olyan sok klienssel rendelkező program, ahol minden kliens üzenetet kap, amikor egy másik kliens valamilyen műveletet végez (chat szobák esetén ez olyan, mintha minden ember küldenek egy üzenetet). A valóságban a Mediátor minta használata chat szobákhoz csak akkor lenne praktikus, ha távoli eléréssel használnánk. Egyéb esetben nem lenne lehetséges a delegáltak visszahívása (azok, akik feliratkoztak a mediátor osztály MessageReceived eseményére).
namespace IVSR.DesignPatterns.Mediator
{
public delegate void MessageReceivedEventHandler(string message, string from);
public class Mediator
{
public event MessageReceivedEventHandler MessageReceived;
public void Send(string message, string from)
{
if (MessageReceived != null)
{
Console.WriteLine("Sending '{0}' from {1}", message, from);
MessageReceived(message, from);
}
}
}
public class Person
{
private Mediator _mediator;
public string Name
{
get;
set;
}
public Person(Mediator mediator, string name)
{
Name = name;
_mediator = mediator;
_mediator.MessageReceived += new MessageReceivedEventHandler(Receive);
}
private void Receive(string message, string from)
{
if (from != Name)
Console.WriteLine("{0} received '{1}' from {2}", Name, message, from);
}
public void Send(string message)
{
_mediator.Send(message, Name);
}
}
}
Java
szerkesztésAz alábbi mintában a mediátor objektum három összetartozó gomb állapotát szabályozza: ehhez három függvényt alkalmaz (book()
, view()
, search()
), melyekkel beállítja a gombok státuszát. A függvényeket a gombok aktiválásával lehet meghívni (a bennük található execute()
utasítások keresztül).
Emiatt itt az együttműködési mintában minden résztvevő (a gombok) közli tevékenységét a mediátorral, amely elküldi nekik az elvárt viselkedést.
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
//Colleague interfész
interface Command {
void execute();
}
//absztrakt Mediator
interface Mediator {
void book();
void view();
void search();
void registerView(BtnView v);
void registerSearch(BtnSearch s);
void registerBook(BtnBook b);
void registerDisplay(LblDisplay d);
}
//ConcreteMediator
class ParticipantMediator implements Mediator {
BtnView btnView;
BtnSearch btnSearch;
BtnBook btnBook;
LblDisplay show;
//....
public void registerView(BtnView v) {
btnView = v;
}
public void registerSearch(BtnSearch s) {
btnSearch = s;
}
public void registerBook(BtnBook b) {
btnBook = b;
}
public void registerDisplay(LblDisplay d) {
show = d;
}
public void book() {
btnBook.setEnabled(false);
btnView.setEnabled(true);
btnSearch.setEnabled(true);
show.setText("booking...");
}
public void view() {
btnView.setEnabled(false);
btnSearch.setEnabled(true);
btnBook.setEnabled(true);
show.setText("viewing...");
}
public void search() {
btnSearch.setEnabled(false);
btnView.setEnabled(true);
btnBook.setEnabled(true);
show.setText("searching...");
}
}
//ConcreteColleague
class BtnView extends JButton implements Command {
Mediator med;
BtnView(ActionListener al, Mediator m) {
super("View");
addActionListener(al);
med = m;
med.registerView(this);
}
public void execute() {
med.view();
}
}
//ConcreteColleague
class BtnSearch extends JButton implements Command {
Mediator med;
BtnSearch(ActionListener al, Mediator m) {
super("Search");
addActionListener(al);
med = m;
med.registerSearch(this);
}
public void execute() {
med.search();
}
}
//ConcreteColleague
class BtnBook extends JButton implements Command {
Mediator med;
BtnBook(ActionListener al, Mediator m) {
super("Book");
addActionListener(al);
med = m;
med.registerBook(this);
}
public void execute() {
med.book();
}
}
class LblDisplay extends JLabel {
Mediator med;
LblDisplay(Mediator m) {
super("Just start...");
med = m;
med.registerDisplay(this);
setFont(new Font("Arial", Font.BOLD, 24));
}
}
class MediatorDemo extends JFrame implements ActionListener {
Mediator med = new ParticipantMediator();
MediatorDemo() {
JPanel p = new JPanel();
p.add(new BtnView(this, med));
p.add(new BtnBook(this, med));
p.add(new BtnSearch(this, med));
getContentPane().add(new LblDisplay(med), "North");
getContentPane().add(p, "South");
setSize(400, 200);
setVisible(true);
}
public void actionPerformed(ActionEvent ae) {
Command comd = (Command) ae.getSource();
comd.execute();
}
public static void main(String[] args) {
new MediatorDemo();
}
}