Mediator (Mellanhand)
Introduktion
Mediator är ett beteendemönster som minskar kaotiska beroenden mellan objekt. Det begränsar direkt kommunikation mellan objekt och tvingar dem att samarbeta via ett mediatorobjekt.
Problem
Du bygger ett chattrum. Varje användare skickar meddelanden direkt till alla andra användare. Med 10 användare har varje användare 9 direktkopplingar — totalt 45 kopplingar. Lägg till en ny funktion som “tystar en användare” och du måste ändra logiken i varje användarklass.
Lösning
Mediator introducerar ett centralt objekt som hanterar all kommunikation. Komponenterna känner bara till mediatorn — inte till varandra. Komponenterna är löst kopplade och lätta att återanvända.
När ska Mediator användas?
- När klasser är för hårt kopplade till varandra och förändring av en klass kräver ändringar i andra.
- När du inte kan återanvända en komponent eftersom den är beroende av för många andra.
- För chattrum, flygledningssystem, UI-formulär där komponenter påverkar varandra.
Struktur
| Roll | Ansvar |
|---|---|
| Mediator Interface | Definierar kommunikationsgränssnittet som komponenter använder. |
| Concrete Mediator | Koordinerar kommunikationen mellan komponenter; känner till alla. |
| Component | Utför eget arbete; kommunicerar bara via mediatorn. |
Exempel — Chattrum (Java)
Scenariot: Ett chattrum där användare kommunicerar via en ChatRoom-mediator. Mediatorn hanterar regler som att tysta användare och privata meddelanden.
import java.util.ArrayList;
import java.util.List;
// ── Mediator Interface ────────────────────────────────────
public interface ChatMediator {
void register(User user);
void sendMessage(String message, User sender);
void sendPrivate(String message, User sender, String recipientName);
void mute(String username);
}
// ── Component ─────────────────────────────────────────────
public class User {
private final String name;
private final ChatMediator mediator;
public User(String name, ChatMediator mediator) {
this.name = name;
this.mediator = mediator;
mediator.register(this);
}
public String getName() { return name; }
public void send(String message) {
System.out.println("[" + name + "] → Alla: " + message);
mediator.sendMessage(message, this);
}
public void sendTo(String message, String recipient) {
System.out.println("[" + name + "] → " + recipient + " (privat): " + message);
mediator.sendPrivate(message, this, recipient);
}
public void receive(String message, String fromName) {
System.out.println(" ✉️ " + name + " fick från " + fromName + ": " + message);
}
}
// ── Concrete Mediator ─────────────────────────────────────
public class ChatRoom implements ChatMediator {
private final List<User> users = new ArrayList<>();
private final List<String> muted = new ArrayList<>();
@Override
public void register(User user) {
users.add(user);
System.out.println("📢 " + user.getName() + " gick med i chatten.");
}
@Override
public void sendMessage(String message, User sender) {
if (muted.contains(sender.getName())) {
System.out.println(" 🔇 " + sender.getName() + " är tystad — meddelandet blockerades.");
return;
}
for (User user : users) {
if (user != sender) {
user.receive(message, sender.getName());
}
}
}
@Override
public void sendPrivate(String message, User sender, String recipientName) {
users.stream()
.filter(u -> u.getName().equals(recipientName))
.findFirst()
.ifPresentOrElse(
u -> u.receive("🔒 " + message, sender.getName()),
() -> System.out.println(" ❌ Användaren " + recipientName + " finns inte.")
);
}
@Override
public void mute(String username) {
muted.add(username);
System.out.println("🔇 " + username + " har tystats av administratören.");
}
}
// ── Klientkod ─────────────────────────────────────────────
public class Application {
public static void main(String[] args) {
ChatRoom room = new ChatRoom();
User anna = new User("Anna", room);
User bjorn = new User("Björn", room);
User cecilia = new User("Cecilia", room);
System.out.println();
anna.send("Hej alla!");
System.out.println();
bjorn.send("Tjena Anna!");
System.out.println();
anna.sendTo("Ses vi efter mötet?", "Cecilia");
System.out.println();
room.mute("Björn");
bjorn.send("Det här borde ingen se...");
System.out.println();
cecilia.send("Vad hände med Björn?");
}
}
Output:
📢 Anna gick med i chatten.
📢 Björn gick med i chatten.
📢 Cecilia gick med i chatten.
[Anna] → Alla: Hej alla!
✉️ Björn fick från Anna: Hej alla!
✉️ Cecilia fick från Anna: Hej alla!
[Björn] → Alla: Tjena Anna!
✉️ Anna fick från Björn: Tjena Anna!
✉️ Cecilia fick från Björn: Tjena Anna!
[Anna] → Cecilia (privat): Ses vi efter mötet?
✉️ Cecilia fick från Anna: 🔒 Ses vi efter mötet?
🔇 Björn har tystats av administratören.
[Björn] → Alla: Det här borde ingen se...
🔇 Björn är tystad — meddelandet blockerades.
[Cecilia] → Alla: Vad hände med Björn?
✉️ Anna fick från Cecilia: Vad hände med Björn?
✉️ Björn fick från Cecilia: Vad hände med Björn?
Fördelar
- Single Responsibility Principle — Kommunikationslogiken är samlad i mediatorn.
- Open/Closed Principle — Lägg till nya komponenter utan att ändra befintliga.
- Komponenterna är löst kopplade och lätta att återanvända i andra sammanhang.
Nackdelar
- Mediatorn kan växa till ett God Object om för mycket logik samlas där.
Av Victor Hernandez från Bytebase.se