Last active
January 4, 2017 04:43
-
-
Save ghsyeung/44598be056fec830ee296ddb422db9bb to your computer and use it in GitHub Desktop.
Dependency Injection Distilled
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class Foo { | |
constructor(private _bar: Bar) {} | |
} | |
class Bar {} | |
const bar = new Bar(); | |
const foo = new Foo(bar); | |
// Do the above for like 500 lines...finally you can use it | |
foo.doSomething(); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class FooModel {} | |
class BarModel {} | |
class DBModule { | |
public fooModel: FooModel; | |
public barModel: BarModel; | |
constructor() { | |
this.fooModel = new FooModel(); | |
this.barModel = new BarModel(); | |
} | |
} | |
class BarStatisticsModule { | |
public barStatisticsCalculator: BarStatisticsCalculator; | |
construtor(dbModule:DBModule) { | |
this.barStatisticsCalculator = new BarStatisticsCalculator(dbModule.barModel); | |
} | |
} | |
const dbModule = new DBModule(); | |
const barStatisticsModule = new BarStatisticsModule(dbModule); | |
// To Use | |
barStatisticsModule.barStatisticsCalculator.doSomething(); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Let's define functions as a type | |
type F0<R> = () => R; | |
type F1<A1, R> = (a: A1) => R; | |
type F2<A1, A2, R> = (a1: A1, a2: A2) => R; | |
type ReportType = 'FancyReport' | 'ConsoleReport'; | |
interface BarStatistics extends Statistics {} | |
// The Typescript syntax is a bit archaic (you need to repeat it twice) but bare with me | |
function BarStatisticsReport({ getBars, generateStatistics, getReportWriter, generateReportFromStatistics }:{ | |
// Here are my dependencies | |
getBar: F1<BarID[], Bar[]>, | |
generateStatistics: F1<Bar[], BarStatistics>, | |
getReportWriter: F1<ReportType, ReportWriter<ReportType>>, | |
generateReportFromStatistics: F2<BarStatistics, ReportWriter<ReportType>, Report> | |
}):F2<BarID[], ReportType, Report> { | |
// Here I am returning the constructed function | |
return (barIds: BarID[], reportType:ReportType) => { | |
const bars = getBar(barIds); | |
const stats = generateStatistics(bars); | |
const reportWriter = getReportWriter(reportType); | |
return generateReportFromStatistics(stats, reportWriter); | |
}; | |
} | |
// Here's the dependency injection | |
const fn_barStatisticsReport = BarStatisticsReport({ | |
// I am assuming all the following functions are already created similar to this | |
getBars: getBars, | |
generateStatistics: generateStatistics, | |
getReportWriter: (type:ReportType) => reportWriterRepo.get(type), | |
generateReportFromStatistics: generateReportFromStatistics, | |
}); | |
// To use | |
const fancyReport = fn_barStatisticsReport([ 'bar1', 'bar2', 'bar3' ], 'FancyReport'); | |
/** | |
* If you haven't read the benefit analysis portion, I challenge you to think about the following question | |
* Which approach do you think would be easier to write test for? Or are they the same? | |
* 1) for Isolation tests | |
* 2) for Integration tests | |
* 3) for E2E tests | |
*/ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment