Skip to content

imdoroshenko/registerjs

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

36 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

registerjs

####Basic example Let us create simple service that greet user. It's required output method and greeting pharse.

// Greeter service
const Greeter = function ($greetOutputMethod, $greetPhrase) {
  this.outputMethod = $greetOutputMethod
  this.pharse = $greetPhrase
}
Greeter.prototype.greet = function (name) {
  this.outputMethod(this.pharse + ' ' + name + '!')
}
// console output method
function consoleOut(str) {
  console.log(str)
}
// alert output method
function alertOut(str) {
  window.alert(str)
}

You basically can use this service without any DI framework. But in this case you must remember and handle it dependencies in every place you want instantiate this service.

const 
  consoleGreeter = new Greeter(consoleOut, 'Hello'),
  alertGreeter = new Greeter(alertOut, 'Hey')
  
consoleGreeter.greet('Mike') //will output "Hello Mike!" in browser console
alertGreeter.greet('Alex') //will output "Hey Alex!" through browser alert 

With registerjs you can create two DI containers with different dependencied for Greeter.

rg.registerClass('ConsoleGreeter', Greeter, {
  greetOutputMethod: consoleGreeter,
  greetPhrase: 'Hello'
})
rg.registerClass('AlertGreeter', Greeter, {
  greetOutputMethod: alertOut,
  greetPhrase: 'Hey'
})

Now lets try to use Greeter in registerjs way

const 
  consoleGreeter = rg.getInstance('ConsoleGreeter'),
  alertGreeter = rg.getInstance('AlertGreeter')
consoleGreeter.greet('Mike') //will output "Hello Mike!" in browser console
alertGreeter.greet('Alex') //will output "Hey Alex!" through browser alert 

As you can see, now you do not need to handle dependencies for Greeter. You simple use DI containers, Although entities consoleGreeter and alertGreeter is still instances of Greeter.

console.log(consoleGreeter instanceof Greeter) //true
console.log(alertGreeter instanceof Greeter) //true

####Register Injection In expample with Greeter we declared it dependencies in moment of creation DI container. This dependencies will be attached to DI container, and used by default with highest priority. But there is others approaches to declare dependencied.

// Lets create Service with two dependencies but register only with one of them.
const Service = function ($firstDependency, $secondDependency) {
 console.log($firstDependency, $secondDependency)
}
rg.registerClass('Service', Service, {firstDependency : 'Dependency attached to DI container'})
// Second dependency we will register in global registerjs injections repository
rg.registerInjection('secondDependency', 'dependency from registerjs repository')
// Now lets instantiate this Service
rg.getInstance('Service') //'Dependency attached to DI container', 'dependency from registerjs repository'

So when you instantiate registerjs class he will look for DI container dependencies in first place, then he will check registerjs injections repository, in last place he will check global namespace. So next approach will works too.

rg.registerClass('Service', function ($firstDependency, $secondDependency) {
 console.log($firstDependency, $secondDepenency)
})
const 
  firstDependency = 'first dependency from global ns',
  secondDepenency = 'the second one'
rg.getInstance('Service') //'first dependency from global ns', 'the second one'

####Arguments DI container still allow you to pass arguments to class constructor

rg.registerClass('Service', 
  function ($firstDependency, fisrtArgument,  $secondDependency, secondArgument) {
 console.log('$firstDependency ->', $firstDependency)
 console.log('fisrtArgument ->', fisrtArgument)
 console.log('$secondDepenency ->', $secondDependency)
 console.log('secondArgument ->', secondArgument)
})
rg.registerInjections({
 firstDependency: 'first dependency',
 secondDependency: 'second dependency',
})
rg.getInstance('Service', 'first argument', 'second argument')

output:

$firstDependency -> first dependency 
fisrtArgument -> first argument 
$secondDepenency -> second dependency 
secondArgument -> second argument 

####Advanced example Registerjs allow you to create bunch of services with deep dependencied.

const
  Registerjs = require('../src/register'),
  rg = new Registerjs

/**
 * CoffeeMaker
 * @param {Grinder} $grinder
 * @param {Pump} $pump
 */
const CoffeeMaker = function ($grinder, $pump) {
  this.grinder = $grinder
  this.pump = $pump
}
CoffeeMaker.prototype.brew = function (name) {
  console.log('brewing coffee for ' + name)
  this.grinder.grind()
  this.pump.pump()
}
/**
 * Electricity class
 */
const Electricity = function () {}
Electricity.prototype.use = function (user) {
  console.log('electricity used by ' + user)
}
/**
 * Grinder
 * @param {Electricity} $electricity
 * @param {String} $coffee
 */
const Grinder = function ($electricity, $coffee) {
  this.electricity = $electricity
  this.coffee = $coffee
}
Grinder.prototype.grind = function () {
  this.electricity.use('Grinder')
  console.log('Coffee ' + this.coffee + ' is grind in Grinder')
}
/**
 * Heater
 * @param {Electricity} $electricity
 */
const Heater = function ($electricity) {
  this.electricity = $electricity
}
Heater.prototype.boil = function () {
  this.electricity.use('Heater')
  console.log('boil water in Heater')
}
/**
 * Pump
 * @param {Heater} $heater
 * @param {Electricity} $electricity
 */
const Pump = function ($heater, $electricity) {
  this.heater = $heater
  this.electricity = $electricity
}
Pump.prototype.pump = function () {
  console.log('Pump water trough Heater')
  this.electricity.use('Pump')
  this.heater.boil()
}

Lets use this classes by manualy handle their dependencies

const 
  coffee = 'Jacobs',
  electricity = new Electricity(),
  grinder = new Grinder(electricity, coffee),
  heater = new Heater(electricity),
  pump = new Pump(heater, electricity),
  coffeeMaker = new CoffeeMaker(grinder, pump)

coffeeMaker.brew('Mike')

output:

brewing coffee for Mike
electricity used by Grinder
Coffee Jacobs is grind in Grinder
Pump water trough Heater
electricity used by Pump
electricity used by Heater 
boil water in Heater  

Simple, but it is easy to mess, and you probably need to create factories or strategies to keep Open/closed principle. Lets try to use this classes in registerjs way.

rg.registerClasses(
    ['coffeeMaker', CoffeeMaker],
    ['grinder', Grinder],
    ['heater', Heater],
    ['pump', Pump]
)
// Electricity does not have any dependencies
// and we want to use single instance of it in all our classes
// so lets register it like simple injection
rg.registerInjections(
    ['electricity', new Electricity()],
    ['coffee', 'Jacobs']
)

rg.getInstance('coffeeMaker').brew('Mike')

output:

brewing coffee for Mike
electricity used by Grinder
Coffee Jacobs is grind in Grinder
Pump water trough Heater
electricity used by Pump
electricity used by Heater
boil water in Heater 

About

dependency injection

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published