Blog Infos
Author
Published
Topics
, , ,
Published
Purpose of the pattern

Mediator is made for 1 thing only: Reducing Chaos between dependencies. Objects, instead of communicating with each other directly, will communicate through the Mediator.

What do we get from that?
  • Less coupled code: classes don’t use multiple external dependencies.
  • Reusability: classes don’t depend on each other and can be reused in other projects and places.
  • Single Responsibility: communication responsibility is moved to the Mediator, making it easier to maintain and analyze.
  • Open/Closed: introducing new Mediators doesn’t require changing any code in the existing codebase.

The biggest downside? Mediator might become a large monolith object with thousands of lines.

Implementation
Mediator class diagram

 

The diagram above Mediator is an interface because we don’t want Colleague to depend on concrete classes but on abstraction. MediatorImpl is a concrete class that depends on all the Colleague concrete classes. We’re cleaning our codebase, but at the same time, we introduce very dirty MediatorImpl with multiple dependencies.

  1. Identify a group of tightly coupled classes that could be reused or are too dependent on each other, making your system too complex.
  2. Declare Mediator interface.
  3. Create a concrete Mediator class that includes all the necessary dependencies.
  4. Add Mediator interface reference to the group of objects and remove previous dependencies.
  5. Change the code so that it calls Mediator instead of other classes.
Example

Your task is to make a Chat app with a group system. Each Chatter is in a group, can send and receive messages from other Chatter s. We’ll use Mediator to control messages sent to groups by Chatters . Here’s how we’ll structure our code:

Example class diagram

Job Offers

Job Offers

There are currently no vacancies.

OUR VIDEO RECOMMENDATION

, ,

Migrating to Jetpack Compose – an interop love story

Most of you are familiar with Jetpack Compose and its benefits. If you’re able to start anew and create a Compose-only app, you’re on the right track. But this talk might not be for you…
Watch Video

Migrating to Jetpack Compose - an interop love story

Simona Milanovic
Android DevRel Engineer for Jetpack Compose
Google

Migrating to Jetpack Compose - an interop love story

Simona Milanovic
Android DevRel Engin ...
Google

Migrating to Jetpack Compose - an interop love story

Simona Milanovic
Android DevRel Engineer f ...
Google

Jobs

Note that ChatMediator has a join method that needs to be called by the Chatters to receive messages.

Let’s start by adding Group :

enum class Group {
    SPORT,
    STUDENT;
}

For simplicity, we’ll only have 2 groups. Now, let’s define ChatMediator interface so we can create Chatters :

interface ChatMediator {
    fun send(message: String, group: Group)
    fun join(chatter: Chatter)
}

Now, let’s add Chatter along with SportsChatter and UniversityChatter :

interface Chatter {
    fun send(message: String, group: Group)
    fun receive(message: String)
    val groups: Set<Group>
}

class SportsChatter(private val mediator: ChatMediator) : Chatter {
    init {
        mediator.join(this)
    }

    override fun send(message: String, group: Group) {
        mediator.send(message, group)
    }

    override fun receive(message: String) {
        print("Sports received $message")
    }

    override val groups: Set<Group>
        get() = setOf(Group.SPORT)
}
// For simplicity this class is almost identical to SportsChatter
class UniversityChatter(private val mediator: ChatMediator) : Chatter {
    init {
        mediator.join(this)
    }

    override fun send(message: String, group: Group) {
        mediator.send(message, group)
    }

    override fun receive(message: String) {
        print("University received $message")
    }

    // Note that we have 2 Groups here!!
    override val groups: Set<Group>
        get() = setOf(Group.SPORT, Group.STUDENT)
}

Please note that UniversityChatter belongs to 2 groups Group.SPORT and Group.STUDENT . Finally, let’s implement GroupedChatMediator :

class GroupedChatMediator : ChatMediator {
    private val chatters = mutableListOf<Chatter>()

    override fun send(message: String, group: Group) {
        chatters.forEach { chatter ->
            if (chatter.groups.contains(group)) {
                chatter.receive(message)
            }
        }
    }

    override fun join(chatter: Chatter) {
        chatters.add(chatter)
    }
}

Here’s how to use it:

fun main() {
    val chatMediator: ChatMediator = GroupedChatMediator()

    val sportsChatter: Chatter = SportsChatter(chatMediator)
    val universityChatter: Chatter = UniversityChatter(chatMediator)

    universityChatter.send("Student ", Group.STUDENT) // University
    sportsChatter.send("Sport ", Group.SPORT) // University + Sports
    
    // We can add in more Chatters
    val sportsChatter2: Chatter = SportsChatter(chatMediator)
    sportsChatter2.send("Sport ", Group.SPORT) // University + Sports + Sports
}

And that’s it Mediator is implemented! Well done.

Thanks for reading! Please clap if you learned something, and follow me for more!

Learn more about design patterns:

https://medium.com/@michalankiersztajn/list/design-patterns-in-kotlin-12e52466affe?source=post_page—–543f75bebe69——————————–

Based on the book:

“Wzorce projektowe : elementy oprogramowania obiektowego wielokrotnego użytku” — Erich Gamma Autor; Janusz Jabłonowski (Translator); Grady Booch (Introduction author); Richard Helm (Author); Ralph Johnson (Author); John M Vlissides (Author)

This article is previously published on proandroiddev.com

 

YOU MAY BE INTERESTED IN

YOU MAY BE INTERESTED IN

blog
It’s one of the common UX across apps to provide swipe to dismiss so…
READ MORE
blog
Hi, today I come to you with a quick tip on how to update…
READ MORE
blog
Automation is a key point of Software Testing once it make possible to reproduce…
READ MORE
blog
Drag and Drop reordering in Recyclerview can be achieved with ItemTouchHelper (checkout implementation reference).…
READ MORE

Leave a Reply

Your email address will not be published. Required fields are marked *

Fill out this field
Fill out this field
Please enter a valid email address.

Menu