Observer Pattern in Scala
Published: 2023-04-30 14:48:15

Observer pattern has two main components — Subject and Observer. All observers subscribe to the subject, and in case of any kind of change, the subject is responsible for propagating that information to all observers. As you may have guessed, it sounds like a one-to-many dependency between objects. Let’s have a look at the UML diagram to get a better understanding.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9bcruw6l3rottbh2jm4a.gif)

## Let’s breakdown the structure now
**Subject**
1. Maintains a collection of all the observers.
2. Provides an interface to attach and detach the observers.

**Observer**
1. Defines an updating interface for objects that should be notified of changes in the subject.

**ConcreteSubject**
1. Stores the state of interest to ConcreteObserver.
2. Sends a notification to its observers when it’s state changes.

**ConcreteObserver**
1. Maintains a reference to ConcreteSubject.
2. Might store state that should stay consistent with the subject’s state.
3. Implements the Observer updating interface to keep its state consistent with the subject.

## Implementation
Consider a stock company that tells its users the real-time value of all the stocks. The subject will be the stock company, and all the users who subscribe to it will be its observers.

## CODE

**User.scala**

```
sealed trait Observer {
  def publishUpdate(stocks: mutable.Map[Int, Stock]): Unit
}

case class User(name: String, uuid: String) extends Observer:
  def publishUpdate(stocks: mutable.Map[Int, Stock]): Unit =
    println(name + " " + stocks.values.map(x => x.name + " " + x.price))

```

**StockCompany.scala**

```
case class Stock(id: Int, name: String, price: Double)

sealed trait Subject {
  def registerNewUser(user: User): Unit
  def notifyUser(): Unit
  def deleteUser(user: User): Unit
  def registerStocks(stock: Stock): Unit
  def updateStockPrice(stock: Stock): Unit
}

object StockCompany extends Subject:
  private val stocks = mutable.TreeMap[Int, Stock]()
  private val users = mutable.TreeMap[String, User]()

  def registerNewUser(user: User): Unit =  // Attach
    users.put(user.uuid, user)
    user.publishUpdate(stocks)             // As soonas a user registers they get the live prices
    
  def notifyUser(): Unit =                 // Notify
    users.foreach(_._2.publishUpdate(stocks))
    
  def deleteUser(user: User): Unit =       // Detach
    users.remove(user.uuid)
    
  def registerStocks(stock: Stock): Unit =
    stocks.put(stock.id, stock)
    notifyUser()
    
  def updateStockPrice(stock: Stock): Unit =
    stocks.put(stock.id, stock)
    notifyUser()
```

**MainRunner.scala**

```
object MainRunner:
  def main(args: Array[String]): Unit =
    val user1 = User("user1", "ADBPR4561E")
    val user2 = User("user2", "BFTPD3461S")

    val stock1 = Stock(1, "stock1", 23.42)
    val stock2 = Stock(2, "stock2", 34.53)
    val stock3 = Stock(3, "stock3", 45.64)

    StockCompany.registerStocks(stock1)
    StockCompany.registerStocks(stock2)

    StockCompany.registerNewUser(user1)
    Thread.sleep(1000)
    StockCompany.registerNewUser(user2)
    Thread.sleep(1000)
    StockCompany.registerStocks(stock3)
    Thread.sleep(1000)
    StockCompany.updateStockPrice(Stock(3, "stock3", 123.45))

```


## Known Uses and Related Patterns

This pattern can be used in any scenario, when the user has to be notified in case of any event/change occurs, like:
1. Mobile app for weather update
2. Stock Prices getting updated live on WebPages
3. Ticket confirmation
4. Notification from any application
5. Following a user on Instagram 😂
6. “Notify me” when available on e-commerce sites
7. Event listener on a button

Now, if you give it a thought, the StockCompany has to take care of a lot of things. If we can somehow segregate the task and add another layer of abstraction (say a PriceManager) which will take care of notifying all the users, the stock company will just have to produce the prices to Price Manager and users will subscribe to Price manager while the Price manager orchestrates everything. This is kind of like a Publisher-Subscriber model(can be called a mediator model too based on the implementation)