noncom
noncom

Reputation: 4992

Scala - implementing "manager" pattern in companion object?

When I was programming in Java, I used to have objects and managers for them. You know, a class (typically singleton), which would hold a collection of objects of a certain class and let to conviniently manage them. Now, in Scala, I am finding myself more and more in the situation, where it is quite tempting to put all that functionality in a companion object and avoid creating the distinct manager object.

It all starts with giving IDs to instances and then... why not having the collection in the companion object? And if the collection is there, why not having all the methods to work with the collection in there? And so, the manager is not needed anymore. However, one pecularity is that the companion object usually has a single name like Car (not like Cars or CarManager which presume plurality), so methods that operate with plurals look weird in their coupled wording with the object name.

I would like to know your opinion on this situation and to know if this approach is preferable over the so-seemed unnecessary bloated manager pattern. Any references to any articles on that would also be appreciated.

Upvotes: 2

Views: 378

Answers (2)

thoredge
thoredge

Reputation: 12661

As simple as possible is good; and a collection inside an object is indeed simple. However you should also avoid making your objects dependent on static object. That will create a rigid structure and will make testing more difficult.

I would take a look at the cake-pattern (see How do you do dependency injection with the Cake pattern without hardcoding?). This way you can have the CarManager in an object and mix it into your dependencies through a CarRepositoryComponent.

Non-compiled example:

val someService = new SomeService 
  with MyRepairServiceComponent with CarCollectionRepositoryComponent
someService.repairCar(8)

trait SomeService extends RepairServiceComponent with CarRepositoryComponent {
  def repairCar(id: Int): Status = repairService.repair(carRepository.get(id));
}

trait CarRepository {
  abstract def get(id: Int): Car
}
trait CarRepositoryComponent {
  abstract def carRepository: CarRepository
} 

object CarManager extends CarRepository {
  private var cars = Map[Int, Car]()
  def get(id: Int): Car = cars(id)
}
trait CarCollectionRepositoryComponent {
  def carRepository = CarManager
}

Upvotes: 4

Sean Parsons
Sean Parsons

Reputation: 2832

That's effectively turning a companion object into a singleton which is more of an anti-pattern than a pattern of good design. Unit testing is the main reason for this being an issue (this has been covered many times before by many people smarter than me).

An object ideally shouldn't maintain mutable state of any kind for these reasons (it'll lead to a maintenance nightmare trust me).

Upvotes: 3

Related Questions