In software engineering, the mediator pattern defines an object that encapsulates how a set of objects interact. This pattern is considered to be a behavioral pattern due to the way it can alter the program's running behavior.
In object-oriented programming, programs often consist of many classes. Business logic and computation are distributed among these classes. However, as more classes are added to a program, especially during maintenance and/or refactoring, the problem of communication between these classes may become more complex. This makes the program harder to read and maintain. Furthermore, it can become difficult to change the program, since any change may affect code in several other classes.
With the mediator pattern, communication between objects is encapsulated within a mediator object. Objects no longer communicate directly with each other, but instead communicate through the mediator. This reduces the dependencies between communicating objects, thereby reducing coupling.
The mediator [1] design pattern is one of the twenty-three well-known design patterns that describe how to solve recurring design problems to design flexible and reusable object-oriented software, that is, objects that are easier to implement, change, test, and reuse.
Source: [2]
Defining a set of interacting objects by accessing and updating each other directly is inflexible because it tightly couples the objects to each other and makes it impossible to change the interaction independently from (without having to change) the objects. And it stops the objects from being reusable and makes them hard to test.
Tightly coupled objects are hard to implement, change, test, and reuse because they refer to and know about many different objects.
The objects interact with each other indirectly through a mediator object that controls and coordinates the interaction.
This makes the objects loosely coupled. They only refer to and know about their mediator object and have no explicit knowledge of each other.
See also the UML class and sequence diagram below.
The essence of the mediator pattern is to "define an object that encapsulates how a set of objects interact". It promotes loose coupling by keeping objects from referring to each other explicitly, and it allows their interaction to be varied independently. [3] [4] Client classes can use the mediator to send messages to other clients, and can receive messages from other clients via an event on the mediator class.
In the above UML class diagram, the Colleague1
and Colleague2
classes do not refer to (and update) each other directly. Instead, they refer to the common Mediator
interface for controlling and coordinating interaction (mediate()
), which makes them independent from one another with respect to how the interaction is carried out. The Mediator1
class implements the interaction between Colleague1
and Colleague2
.
The UML sequence diagram shows the run-time interactions. In this example, a Mediator1
object mediates (controls and coordinates) the interaction between Colleague1
and Colleague2
objects.
Assuming that Colleague1
wants to interact with Colleague2
(to update/synchronize its state, for example), Colleague1
calls mediate(this)
on the Mediator1
object, which gets the changed data from Colleague1
and performs an action2()
on Colleague2
.
Thereafter, Colleague2
calls mediate(this)
on the Mediator1
object, which gets the changed data from Colleague2
and performs an action1()
on Colleague1
.
Mediator - defines the interface for communication between Colleague objects
ConcreteMediator - implements the mediator interface and coordinates communication between Colleague objects. It is aware of all of the Colleagues and their purposes with regards to inter-communication.
Colleague - defines the interface for communication with other Colleagues through its Mediator
ConcreteColleague - implements the Colleague interface and communicates with other Colleagues through its Mediator
The mediator pattern ensures that components are loosely coupled, such that they do not call each other explicitly, but instead do so through calls to a mediator. In the following example, the mediator registers all Components and then calls their SetState
methods.
interfaceIComponent{voidSetState(objectstate);}classComponent1:IComponent{internalvoidSetState(objectstate){thrownewNotImplementedException();}}classComponent2:IComponent{internalvoidSetState(objectstate){thrownewNotImplementedException();}}// Mediates the common tasksclassMediator{internalIComponentComponent1{get;set;}internalIComponentComponent2{get;set;}internalvoidChangeState(objectstate){this.Component1.SetState(state);this.Component2.SetState(state);}}
A chat room could use the mediator pattern, or a system where many ‘clients’ each receive a message each time one of the other clients performs an action (for chat rooms, this would be when each person sends a message). In reality using the mediator pattern for a chat room would only be practical when used with remoting. Using raw sockets would not allow for the delegate callbacks (people subscribed to the Mediator class’ MessageReceived event).
publicdelegatevoidMessageReceivedEventHandler(stringmessage,stringsender);publicclassMediator{publiceventMessageReceivedEventHandlerMessageReceived;publicvoidSend(stringmessage,stringsender){if(MessageReceived!=null){Console.WriteLine("Sending '{0}' from {1}",message,sender);MessageReceived(message,sender);}}}publicclassPerson{privateMediator_mediator;publicPerson(Mediatormediator,stringname){Name=name;_mediator=mediator;_mediator.MessageReceived+=newMessageReceivedEventHandler(Receive);}publicstringName{get;set;}privatevoidReceive(stringmessage,stringsender){if(sender!=Name)Console.WriteLine("{0} received '{1}' from {2}",Name,message,sender);}publicvoidSend(stringmessage){_mediator.Send(message,Name);}}
In the following example, a Mediator
object controls the values of several Storage
objects, forcing the user code to access the stored values through the mediator. When a storage object wants to emit an event indicating that its value has changed, it also goes back to the mediator object (via the method notifyObservers
) that controls the list of the observers (implemented using the observer pattern).
importjava.util.HashMap;importjava.util.Optional;importjava.util.concurrent.CopyOnWriteArrayList;importjava.util.function.Consumer;classStorage<T>{Tvalue;TgetValue(){returnvalue;}voidsetValue(Mediator<T>mediator,StringstorageName,Tvalue){this.value=value;mediator.notifyObservers(storageName);}}classMediator<T>{privatefinalHashMap<String,Storage<T>>storageMap=newHashMap<>();privatefinalCopyOnWriteArrayList<Consumer<String>>observers=newCopyOnWriteArrayList<>();publicvoidsetValue(StringstorageName,Tvalue){Storagestorage=storageMap.computeIfAbsent(storageName,name->newStorage<>());storage.setValue(this,storageName,value);}publicOptional<T>getValue(StringstorageName){returnOptional.ofNullable(storageMap.get(storageName)).map(Storage::getValue);}publicvoidaddObserver(StringstorageName,Runnableobserver){observers.add(eventName->{if(eventName.equals(storageName)){observer.run();}});}voidnotifyObservers(StringeventName){observers.forEach(observer->observer.accept(eventName));}}publicclassMediatorDemo{publicstaticvoidmain(String[]args){Mediator<Integer>mediator=newMediator<>();mediator.setValue("bob",20);mediator.setValue("alice",24);mediator.getValue("alice").ifPresent(age->System.out.println("age for alice: "+age));mediator.addObserver("bob",()->{System.out.println("new age for bob: "+mediator.getValue("bob").orElseThrow(RuntimeException::new));});mediator.setValue("bob",21);}}
A visitor pattern is a software design pattern that separates the algorithm from the object structure. Because of this separation, new operations can be added to existing object structures without modifying the structures. It is one way to follow the open/closed principle in object-oriented programming and software engineering.
In software engineering, the adapter pattern is a software design pattern that allows the interface of an existing class to be used as another interface. It is often used to make existing classes work with others without modifying their source code.
The bridge pattern is a design pattern used in software engineering that is meant to "decouple an abstraction from its implementation so that the two can vary independently", introduced by the Gang of Four. The bridge uses encapsulation, aggregation, and can use inheritance to separate responsibilities into different classes.
In computer programming, the flyweight software design pattern refers to an object that minimizes memory usage by sharing some of its data with other similar objects. The flyweight pattern is one of twenty-three well-known GoF design patterns. These patterns promote flexible object-oriented software design, which is easier to implement, change, test, and reuse.
The memento pattern is a software design pattern that exposes the private internal state of an object. One example of how this can be used is to restore an object to its previous state, another is versioning, another is custom serialization.
The builder pattern is a design pattern that provides a flexible solution to various object creation problems in object-oriented programming. The builder pattern separates the construction of a complex object from its representation. It is one of the 23 classic design patterns described in the book Design Patterns and is sub-categorized as a creational pattern.
In software engineering, the composite pattern is a partitioning design pattern. The composite pattern describes a group of objects that are treated the same way as a single instance of the same type of object. The intent of a composite is to "compose" objects into tree structures to represent part-whole hierarchies. Implementing the composite pattern lets clients treat individual objects and compositions uniformly.
In object-oriented programming, the decorator pattern is a design pattern that allows behavior to be added to an individual object, dynamically, without affecting the behavior of other instances of the same class. The decorator pattern is often useful for adhering to the Single Responsibility Principle, as it allows functionality to be divided between classes with unique areas of concern as well as to the Open-Closed Principle, by allowing the functionality of a class to be extended without being modified. Decorator use can be more efficient than subclassing, because an object's behavior can be augmented without defining an entirely new object.
In software design and engineering, the observer pattern is a software design pattern in which an object, named the subject, maintains a list of its dependents, called observers, and notifies them automatically of any state changes, usually by calling one of their methods.
In computer programming, the strategy pattern is a behavioral software design pattern that enables selecting an algorithm at runtime. Instead of implementing a single algorithm directly, code receives runtime instructions as to which in a family of algorithms to use.
In computing, type introspection is the ability of a program to examine the type or properties of an object at runtime. Some programming languages possess this capability.
The syntax of Java is the set of rules defining how a Java program is written and interpreted.
In software engineering, dependency injection is a programming technique in which an object or function receives other objects or functions that it requires, as opposed to creating them internally. Dependency injection aims to separate the concerns of constructing objects and using them, leading to loosely coupled programs. The pattern ensures that an object or function that wants to use a given service should not have to know how to construct those services. Instead, the receiving "client" is provided with its dependencies by external code, which it is not aware of. Dependency injection makes implicit dependencies explicit and helps solve the following problems:
In the Java computer programming language, an annotation is a form of syntactic metadata that can be added to Java source code. Classes, methods, variables, parameters and Java packages may be annotated. Like Javadoc tags, Java annotations can be read from source files. Unlike Javadoc tags, Java annotations can also be embedded in and read from Java class files generated by the Java compiler. This allows annotations to be retained by the Java virtual machine at run-time and read via reflection. It is possible to create meta-annotations out of the existing ones in Java.
A delegate is a form of type-safe function pointer used by the Common Language Infrastructure (CLI). Delegates specify a method to call and optionally an object to call the method on. Delegates are used, among other things, to implement callbacks and event listeners. A delegate object encapsulates a reference to a method. The delegate object can then be passed to code that can call the referenced method, without having to know at compile time which method will be invoked.
In software engineering, a fluent interface is an object-oriented API whose design relies extensively on method chaining. Its goal is to increase code legibility by creating a domain-specific language (DSL). The term was coined in 2005 by Eric Evans and Martin Fowler.
In object-oriented computer programming, a null object is an object with no referenced value or with defined neutral (null) behavior. The null object design pattern, which describes the uses of such objects and their behavior, was first published as "Void Value" and later in the Pattern Languages of Program Design book series as "Null Object".
In object-oriented design, the chain-of-responsibility pattern is a behavioral design pattern consisting of a source of command objects and a series of processing objects. Each processing object contains logic that defines the types of command objects that it can handle; the rest are passed to the next processing object in the chain. A mechanism also exists for adding new processing objects to the end of this chain.
The archetype pattern is a software design pattern that separates logic from implementation. The separation is accomplished through the creation of two abstract classes: a decorator, and a delegate. The Factory handles the mapping of decorator and delegate classes and returns the pair associated with a parameter or parameters passed. The interface is the contract between a decorator, a delegate, and the calling class, creating an Inversion of Responsibility. This example use two branches; however, you can have 'N' branches as required. The pattern means that one branch from the interface does not have to worry about how another branch operators as long it implements the interface.
In object-oriented programming, forwarding means that using a member of an object results in actually using the corresponding member of a different object: the use is forwarded to another object. Forwarding is used in a number of design patterns, where some members are forwarded to another object, while others are handled by the directly used object. The forwarding object is frequently called a wrapper object, and explicit forwarding members are called wrapper functions.
{{cite book}}
: CS1 maint: multiple names: authors list (link)