2. Topics CoveredTopics Covered
What is dependency Injection
Why should we use it
Implementations
Live Demo
What is dependency Injection
Why should we use it
Implementations
Live Demo
3. What is DI
● Dependency injection is a software design pattern in which any dependency object has
should be provided that dependency instead of internally create with in an object. The
term DI was coined by Martin Fowler.
● It is an implementation Dependency inversion principle.
The principle states:
a)High-level modules should not depend on low-level modules. Both should depend on
abstractions.
b) Abstractions should not depend on details. Details should depend on abstractions.
4. class UserDAL{
def getUser(id:String):User={
//returning user from database
}
}
class UserService{
val userDAL=new UserDAL()
def getUserInfo(id:String):UserInfo={
val user=userDAL.getUser(id)
// do some operation on user data and return UserInfo
}
}
What is wrong ?
5. class UserDAL{
def getUser(id:String):User={
//returning user from database
}
}
class UserService(userDAL: UserDAL){
def getUserInfo(id:String):UserInfo={
val user=userDAL.getUser(id)
// do some operation on user data and return UserInfo
}
}
Is this correct?
6. class UserDAL{
def getUser(id:String):User={
//returning user from database
}
}
class UserService(userDAL: UserDAL){
def getUserInfo(id:String):UserInfo={
val user=userDAL.getUser(id)
// do some operation on user data and return UserInfo
}
}
Is this correct -No
7. trait UserDALComponent{
def getUser(id:String):User
}
class UserDAL extends UserDALComponent{
def getUser(id:String):User={
//returning user from database
}
}
class UserService(userDAL: UserDALComponent){
def getUserInfo(id:String):UserInfo={
val user=userDAL.getUser(id)
// do some operation on user data and return UserInfo
}
}
8. Why should we use it
● Unit testing
Mock Data Access Layer
Mock File System
Mock Email
● Modular design
Multiple different implementation
Upgradeable infrastructure
● Clean Separations
Single Responsibility
Increase code Re-Use
Cleaner Modeling
● Concurrent or independent development
10. Constructor Injection
// Data Access Layer
trait UserDALComponent {
def getUser(id: String): User
def create(user: User)
def delete(user: User)
}
class UserDAL extends UserDALComponent {
// a dummy data access layer that is not persisting
anything
def getUser(id: String): User = {
val user = User("12334", "testUser",
"test@knoldus.com")
println("UserDAL: Getting user " + user)
user
}
def create(user: User) = {
println("UserDAL: creating user: " + user)
}
def delete(user: User) = {
println("UserDAL: deleting user: " + user)
}
}
case class User(id: String, name: String, email: String)
// User service which have Data Access Layer dependency
class UserService(userDAL: UserDALComponent) {
def getUserInfo(id: String): User = {
val user = userDAL.getUser(id)
println("UserService: Getting user " + user)
user
}
def createUser(user: User) = {
userDAL.create(user)
println("UserService: creating user: " + user)
}
def deleteUser(user: User) = {
userDAL.delete(user)
println("UserService: deleting user: " + user)
}
11. Setter Injection
// Data Access Layer
trait UserDALComponent {
def getUser(id: String): User
def create(user: User)
def delete(user: User)
}
class UserDAL extends UserDALComponent {
// a dummy data access layer that is not persisting
anything
def getUser(id: String): User = {
val user = User("12334", "testUser",
"test@knoldus.com")
println("UserDAL: Getting user " + user)
user
}
def create(user: User) = {
println("UserDAL: creating user: " + user)
}
def delete(user: User) = {
println("UserDAL: deleting user: " + user)
}
}
case class User(id: String, name: String, email: String)
// User service which have Data Access Layer dependency
class UserService() {
private var userDAL: UserDALComponent = _
def setUserDAL(userDAL: UserDALComponent) = {
this.userDAL = userDAL
}
def getUserInfo(id: String): User = {
val user = userDAL.getUser(id)
println("UserService: Getting user " + user)
user
}
def createUser(user: User) = {
userDAL.create(user)
println("UserService: creating user: " + user)
}
def deleteUser(user: User) = {
userDAL.delete(user)
println("UserService: deleting user: " + user)
}
}
12. Cake Pattern
// Data Access Layer
trait UserDALComponent {
val userDAL: UserDAL
class UserDAL {
// a dummy data access layer that is not persisting anything
def getUser(id: String): User = {
val user = User("12334", "testUser", "test@knoldus.com")
println("UserDAL: Getting user " + user)
user
}
def create(user: User) = {
println("UserDAL: creating user: " + user)
}
def delete(user: User) = {
println("UserDAL: deleting user: " + user)
}
}
}
case class User(id: String, name: String, email: String)
// User service which have Data Access Layer dependency
trait UserServiceComponent { this: UserDALComponent =>
val userService: UserService
class UserService {
def getUserInfo(id: String): User = {
val user = userDAL.getUser(id)
println("UserService: Getting user " + user)
user
}
def createUser(user: User) = {
userDAL.create(user)
println("UserService: creating user: " + user)
}
def deleteUser(user: User) = {
userDAL.delete(user)
println("UserService: deleting user: " + user)
}
}
}
13. Cake Implemetation
object User extends UserServiceComponent with UserDALComponent {
val userService = new UserService
val userDAL = new UserDAL
}
object UserApp extends App {
import User.userService._
println(getUserInfo(""))
}
14. Google Guice
// Data Access Layer
trait UserDALComponent {
def getUser(id: String): User
def create(user: User)
def delete(user: User)
}
class UserDAL extends UserDALComponent {
// a dummy data access layer that is not persisting anything
def getUser(id: String): User = {
val user = User("12334", "testUser", "test@knoldus.com")
println("UserDAL: Getting user " + user)
user
}
def create(user: User) = {
println("UserDAL: creating user: " + user)
}
def delete(user: User) = {
println("UserDAL: deleting user: " + user)
}
}
case class User(id: String, name: String, email: String)
// User service which have Data Access Layer dependency
class UserService @Inject()(userDAL: UserDALComponent) {
def getUserInfo(id: String): User = {
val user = userDAL.getUser(id)
println("UserService: Getting user " + user)
user
}
def createUser(user: User) = {
userDAL.create(user)
println("UserService: creating user: " + user)
}
def deleteUser(user: User) = {
userDAL.delete(user)
println("UserService: deleting user: " + user)
}
}
16. Object creation By Guice
val injector = Guice.createInjector(new DependencyModule)
val userService = injector.getInstance(classOf[UserService])
// call userService Methods
userService.createUser(User("212","demo","app"))
17. References
● A very popular blog on DI by Jonas boner:
http://jonasboner.com/2008/10/06/real-world-scala-
● Inversion of Control Containers and the
Dependency Injection pattern By Martin
Fowler:
http://martinfowler.com/articles/injection.html