Git Product home page Git Product logo

svloc's Introduction

A Library for Dependency Injection in Go

svloc Coverage Status

Why this library?

  • It is simpler than uber/fx, yet still powerful
  • Static typing & without using reflection
  • Easy to use and easy to replace objects for unit & integration testing (by using Override, one can replace any part of the default dependency graph)
  • Easy to read & navigate with IDEs
  • Safe to use in multiple goroutines
  • Very easy-to-read stacktraces when something wrong happens
  • Provide default wiring through the Register method, or no default wiring through RegisterEmpty

This library does NOT actually use the Service Locator pattern

Limitations

  • Runtime wiring of objects
  • Deep stack calls
  • Override functions only work outside of the anonymous functions in the Register calls

Installtion

go get github.com/QuangTung97/[email protected]

Examples

Assume RepoImpl implements interface Repo:

package main

type Repo interface {
	GetUser() string
}

type RepoImpl struct {
	name string
}

func NewRepo(name string) *RepoImpl {
	return &RepoImpl{
		name: name,
	}
}

func (r *RepoImpl) GetUser() string {
	return r.name
}

Assume Service with method Hello:

package main

import (
	"fmt"
)

type Service struct {
	rp Repo
}

func NewService(repo Repo) *Service {
	return &Service{
		rp: repo,
	}
}

func (s *Service) Hello() {
	fmt.Println("Hello User:", s.rp.GetUser())
}

We can create Locator[T] objects:

package main

import (
	"github.com/QuangTung97/svloc"
)

var usernameLoc = svloc.RegisterEmpty[string]()

var repoLoc = svloc.Register[Repo](func(unv *svloc.Universe) Repo {
	return NewRepo(
		usernameLoc.Get(unv),
	)
})

var serviceLoc = svloc.Register[*Service](func(unv *svloc.Universe) *Service {
	return NewService(repoLoc.Get(unv))
})

The 3 newly created objects: usernameLoc, repoLoc, serviceLoc are all immutable objects and safe to use concurrently.

The svloc.PreventRegistering will not allow Register functions to be called after that point. Usually at the start of the main() function.

To use in main(), first creates a new Universe. Then call MustOverride() on usernameLoc to provide the username string. And then call the serviceLoc.Get() with that Universe, All of the wiring will happen automatically:

package main

func main() {
	svloc.PreventRegistering()

	unv := svloc.NewUniverse()
	usernameLoc.MustOverride(unv, "user01")

	svc := serviceLoc.Get(unv)
	svc.Hello()
}

Full example:

package main

import (
	"fmt"
	"github.com/QuangTung97/svloc"
)

type Repo interface {
	GetUser() string
}

type RepoImpl struct {
	name string
}

func NewRepo(name string) *RepoImpl {
	return &RepoImpl{
		name: name,
	}
}

func (r *RepoImpl) GetUser() string {
	return r.name
}

type Service struct {
	rp Repo
}

func NewService(repo Repo) *Service {
	return &Service{
		rp: repo,
	}
}

func (s *Service) Hello() {
	fmt.Println("Hello User:", s.rp.GetUser())
}

var usernameLoc = svloc.RegisterEmpty[string]()

var repoLoc = svloc.Register[Repo](func(unv *svloc.Universe) Repo {
	return NewRepo(
		usernameLoc.Get(unv),
	)
})

var serviceLoc = svloc.Register[*Service](func(unv *svloc.Universe) *Service {
	return NewService(repoLoc.Get(unv))
})

func main() {
	svloc.PreventRegistering()

	unv := svloc.NewUniverse()
	usernameLoc.MustOverride(unv, "user01")

	svc := serviceLoc.Get(unv)
	svc.Hello()
}

Using OnShutdown and Shutdown:

package main

var repoLoc = svloc.Register[Repo](func(unv *svloc.Universe) Repo {
	unv.OnShutdown(func() {
		fmt.Println("Shutdown Repo")
	})

	return NewRepo(
		usernameLoc.Get(unv),
	)
})

var serviceLoc = svloc.Register[*Service](func(unv *svloc.Universe) *Service {
	unv.OnShutdown(func() {
		fmt.Println("Shutdown Service")
	})
	return NewService(repoLoc.Get(unv))
})

func main() {
	svloc.PreventRegistering()

	unv := svloc.NewUniverse()
	defer unv.Shutdown()

	usernameLoc.MustOverride(unv, "user01")

	svc := serviceLoc.Get(unv)
	svc.Hello()
}

svloc's People

Contributors

quangtung97 avatar

Stargazers

 avatar  avatar  avatar  avatar

Watchers

 avatar

Forkers

tu-hm

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.