Assume you have a couple of classes,
case class Person(name: String, age: Int)
case class Employee(person: Person, salary: Double)
Lets say for some reason,
- You don't want to change this source, but
- You should be able to add features
save(person)
andsave(employee)
, and - You need clearly separate implementations for both the types,
You start by defining a type class,
trait DBObject[T] {
def save(t: T)
}
Then you define an implementation for each of your types as implicit objects,
implicit object PersonDBO extends DBObject[Person] {
def save(p: Person) = //Do whatever you need to do to save p: Person
}
implicit object EmployeeDBO extends DBObject[Employee] {
def save(e: Employee) = //Do whatever you need to do to save e: Employee
}
And then you define your one single generic save method,
def save[T](obj: T)(implicit dbo: DBObject[T]) = dbo.save(obj)
From then onwards you can use save(employee)
to save employees, and save(person)
to save persons.
Also, if you noticed, let's say you want to add a new type Company
. You can give an implicit save
implementation for that one as well in your most recent part of the code, without touching any of the code you have already written!
case class Company(name: String, employees: List[Employee])
implicit object CompanyDBO extends DBObject[Company] {
def save(c: Company) = //Do whatever you need to do to save c: Company
}
Any other goodies you can think about for Type Classes?
Improving this further,
Instead of defining
PersonDBO
object, let us implement aPersonDBO
class along with implicit type conversion.Firstly this would mean you need to define your type class slightly differently,
And your dbo object as,
Which will then let you call