Посередник (шаблон проектування)

Матеріал з Вікіпедії — вільної енциклопедії.
Перейти до: навігація, пошук

Посередник (англ. Mediator) - шаблон проектування, відноситься до класу шаблонів поведінки.

Призначення[ред.ред. код]

Визначає об'єкт, що інкапсулює спосіб взаємодії множини об'єктів. Посередник забезпечує слабку зв'язаність системи, звільняючи об'єкти від необхідності явно посилатися один на одного, і дозволяючи тим самим незалежно змінювати взаємодії між ними.

Застосовність[ред.ред. код]

Слід використовувати шаблон Посередник у випадках, коли:

  • існують об'єкти, зв'язки між котрими досить складні та чітко задані. Отримані при цьому залежності не структуровані та важкі для розуміння;
  • не можна повторно використовувати об'єкт, оскільки він обмінюється інформацією з багатьма іншими об'єктами;
  • поведінка, розподілена між кількома класами, повинна піддаватися налагодженню без створювання множини підкласів.

Структура[ред.ред. код]

UML діаграма, що описує структуру шаблону проектування Посередник
  • Mediator – посередник:
    • визначає інтерфейс для обміну інформацією з об'єктами Colleague;
  • ConcreteMediator – конкретний посередник:
    • реалізує кооперативну поведінку, координуючи дії об'єктів Colleague;
    • володіє інформацією про колег, та підраховує їх;
  • Класи Colleague – колеги:
    • кожному класу Colleague відомо про свій об'єкт Mediator;
    • усі колеги обмінюються інформацією виключно через посередника, інакше за його відсутності їм довелося б спілкуватися між собою напряму.

Відносини[ред.ред. код]

Колеги посилають запити посередникові та отримують запити від нього. Посередник реалізує кооперативну поведінку шляхом переадресації кожного запиту відповідному колезі (або декільком з них).

Приклади[ред.ред. код]

Java[ред.ред. код]

package example.pattern.mediator;
import java.util.Random;

// Mediator
public class TankCommander {
	private TankDriver driver; 
	private TankGunner gunner;
	private TankLoader loader;
	
	public void setDriver(TankDriver driver) {
		this.driver = driver;
	}
	
	public void setGunner(TankGunner gunner) {
		this.gunner = gunner;
	}

	public void setLoader(TankLoader loader) {
		this.loader = loader;
	}
	
	public void targetDetected(String target) {
		System.out.println("Commander: new target detected!");
		gunner.setWeapon(
				loader.prepareWeapon(target));
		driver.halt();
		gunner.fire(target);
	}
	
	public void noTarget() {
		System.out.println("Commander: no target.");
		gunner.stopFire();
		driver.move();
	}

}

// Colleague
public class TankDriver {
	private TankCommander commander;
	private int fuel = 4;
	
	public TankDriver(TankCommander commander) {
		this.commander = commander;
		this.commander.setDriver(this);
	}
	
	public void move() {
		if (fuel <= 0 ) {
			System.out.println("Driver: no fuel!");
			return;
		}
		System.out.println("Driver: tank is moving!");
		fuel--;
		// looking for a new target
		if ((new Random()).nextInt(2) == 0) {
			commander.targetDetected("armored");
		} else {
			commander.targetDetected("infantry");
		}
	}
	
	public void halt() {
		System.out.println("Driver: tank has halted!");
	}
}

// Colleague
public class TankGunner {
	private TankCommander commander;
	private String weapon = "MachineGun"; 
	
	public TankGunner (TankCommander commander) {
		this.commander = commander;
		this.commander.setGunner(this);
	}

	public void fire(String target) {
		System.out.println("Gunner ["+weapon+"]: " + target + " is under fire!");
		commander.noTarget(); // target is destroyed 
	}
	
	public void stopFire() {
		System.out.println("Gunner ["+weapon+"]: Fire is stoped.");
	}
	
	public void setWeapon(String weapon) {
		this.weapon = weapon;
	}
}

// Colleague
public class TankLoader {
	private TankCommander commander;
	
	public TankLoader (TankCommander commander) {
		this.commander = commander;
		this.commander.setLoader(this);
	}
	
	public String prepareWeapon(String target) {
		String weapon = "MachineGun";
		if (target.equals("armored")) {
			weapon = "Cannon";
		}
		System.out.println("Loader: " + weapon + " is ready!");
		return weapon;
	}
}

Python[ред.ред. код]

"""
Типовий приклад посередника зустрічається у фреймворку(програмному каркасі)
автоматизованого  тестування який складається з чотиртох класів:
TC (TestCategory),
TestManager,
Reporter
DB(Database)
"""
import time


class TC:

    def __init__(self):
        self._tm = tm
        self._bProblem = 0

    def setup(self):
        print("Setting up the Test")
        time.sleep(1)
        self._tm.prepareReporting()

    def execute(self):
        if not self._bProblem:
            print("Executing the test")
            time.sleep(1)
        else:
            print("Problem in setup. Test not executed.")

    def tearDown(self):
        if not self._bProblem:
            print("Tearing down")
            time.sleep(1)
            self._tm.publishReport()
        else:
            print("Test not executed. No tear down required.")

    def setTM(self,TM):
        self._tm = tm

    def setProblem(self, value):
        self._bProblem = value


class Reporter:

    def __init__(self):
        self._tm = None

    def prepare(self):
        print("Reporter Class is preparing to report the results")
        time.sleep(1)

    def report(self):
        print("Reporting the results of Test")
        time.sleep(1)

    def setTM(self,TM):
        self._tm = tm


class DB:

    def __init__(self):
        self._tm = None

    def insert(self):
        print("Inserting the execution begin status in the Database")
        time.sleep(1)
        #Following code is to simulate a communication from DB to TC
        import random
        if random.randrange(1,4) == 3:
            return -1

    def update(self):
        print("Updating the test results in Database")
        time.sleep(1)

    def setTM(self,TM):
        self._tm = tm


class TestManager:

    def __init__(self):
        self._reporter = None
        self._db = None
        self._tc = None

    def prepareReporting(self):
        rvalue = self._db.insert()
        if rvalue == -1:
            self._tc.setProblem(1)
            self._reporter.prepare()

    def setReporter(self, reporter):
        self._reporter = reporter

    def setDB(self, db):
        self._db = db

    def publishReport(self):
        self._db.update()
        rvalue = self._reporter.report()

    def setTC(self,tc):
        self._tc = tc


if __name__ == '__main__':
    reporter = Reporter()
    db = DB()
    tm = TestManager()
    tm.setReporter(reporter)
    tm.setDB(db)
    reporter.setTM(tm)
    db.setTM(tm)
    # For simplification we are looping on the same test.
    # Practically, it could be about various unique test classes and their objects
    while (1):
        tc = TC()
        tc.setTM(tm)
        tm.setTC(tc)
        tc.setup()
        tc.execute()
        tc.tearDown()

Джерела[ред.ред. код]

Література[ред.ред. код]

Алан Шаллоуей, Джеймс Р. Тротт Шаблоны проектирования. Новый подход к объектно-ориентированному анализу и проектированию = Design Patterns Explained: A New Perspective on Object-Oriented Design. — М. : «Вильямс», 2002. — 288 с. — ISBN 0-201-71594-5.