scala - Abstract fields for dependency injection -


in scala, there there wrong using below method of dependency injection.

// define interface trait filestorage {   def readfile(filename:string):outputstream }  // , implementation class s3filestorage extends filestorage {     def readfile(filename:string):outputstream = ??? }  // define our service trait abstract fields need // injected in order construct. implementation details go here. trait filehttpserver {   val filestorage:filestorage    def fetchfile( session:session, filename:string ) = ??? } 

now wire things up

// wire concrete file service use in code // no implementation details should go here, we're wiring filehttpserverl // entire project wired way in central location if desired. object s3filehttpserver extends filehttpserver {     val filestorage = new s3filestorage }  // anonymously val myhttpserver = new filehttpserver {     val filestorage = new s3filestorage }   // or create mocked version testing val mockedhttpserver = new filehttpserver {     val filestorage = mock[filestorage] } 

obviously cake pattern provides more flexibility (particularly around self-types), simpler use cases has less boilerplate, while still providing compile time checking , clean unambiguous interface.

yes, absolutely fine approach. , yes, can use constructor injection, nothing wrong too. constructor injection have propagate dependencies manually, while cake pattern dependencies propagated automatically via self-type annotations. big projects constructor injection lead more boilerplate cake pattern, @ construction site (where create objects , set dependencies between them).

however, have presented not full-fledged cake pattern. in real cake pattern there additional layer around business logic classes, so-called components, , not wire logic classes directly components instead.

trait filestoragecomponent {   def filestorage: filestorage    trait filestorage {     def readfile(filename: string): outputstream   } }  trait s3filestoragecomponent extends filestoragecomponent {   val filestorage = new s3filestorage    class s3filestorage extends filestorage {     def readfile(filename: string): outputstream = ???   } }  trait filehttpservercomponent {   self: filestoragecomponent =>    val filehttpserver = new filehttpserver    class filehttpserver {     def fetchfile(session: session, filename: string) = ???   } }  // wiring  object s3filehttpserver extends filehttpservercomponent s3filestoragecomponent  // anonymous  val server = new filehttpservercomponent s3filestoragecomponent  // mocking  object testfilehttpserver extends filehttpservercomponent filestoragecomponent {   val filestorage = mock[filestorage] } 

in approach there more boilerplate in traits definitions, in return have greater flexibility , clear dependency management on use place. example, here how program entry point in 1 of projects looks like:

object main   extends mainui   defaultactorsmanagercomponent   defaultpreferencesaccesscomponent   defaultmodelcomponent   defaultmainwindowviewcomponent   defaultmainwindowcontrollercomponent   mainwindowreportercomponent   defaultclientactorcomponent   defaultresponseparseractorcomponent   defaultarchiveractorcomponent   defaultmainwindowaccessactorcomponent   defaulturlparsercomponent   defaultlisteneractorcomponent   defaultxmlprettifiercomponent 

all main program components in 1 place. pretty neat imo.


Comments

Popular posts from this blog

java.util.scanner - How to read and add only numbers to array from a text file -

rewrite - Trouble with Wordpress multiple custom querystrings -