singoton

package module
v1.0.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 4, 2023 License: MIT Imports: 3 Imported by: 0

README

Singoton

How do you call an unmarried, 1000 kg man? A singoton.

Centralizing object instances in a single place and covering them with an abstract layer. Also support generics.

go get github.com/KafkaWannaFly/singoton

Guide

Register Objects and Use Them

Step 1: Design struct and interface.

// Path: example/crud.go
package main

// ICrud is an interface for CRUD operations.
type ICrud interface {
	Create(item any)
	Read(id int) any
	Update(item any)
	Delete(id int)
}
// Path: example/user.go
package main

// User is a struct for user data.
type User struct {
    ID   int
    Name string
}

// UserCrud is a struct for user CRUD operations.
type UserCrud struct {
    users []User
}

// Create creates a new user.
func (crud *UserCrud) Create(item any) {
    user := item.(User)
    crud.users = append(crud.users, user)
}

// Read reads a user by id.
func (crud *UserCrud) Read(id int) any {
    for _, user := range crud.users {
        if user.ID == id {
            return user
        }
    }
    return nil
}

// Update updates a user.
func (crud *UserCrud) Update(item any) {
    user := item.(User)
    for i, u := range crud.users {
        if u.ID == user.ID {
            crud.users[i] = user
            return
        }
    }
}

// Delete deletes a user by id.
func (crud *UserCrud) Delete(id int) {
    for i, user := range crud.users {
        if user.ID == id {
            crud.users = append(crud.users[:i], crud.users[i+1:]...)
            return
        }
    }
}

Step 2: Register it with singoton.

// Path: example/main.go
package main

import (
	"github.com/KafkaWannaFly/singoton"
)

func main() {
	// Notice that the interface is registered with the struct implementing it.
	singoton.Register[ICrud](&UserCrud{})
}

Step 3: Use it.

// Path: example/main.go
package main

import (
	"fmt"
	"github.com/KafkaWannaFly/singoton"
)

func useCrud() {
	// If can't find the registered struct, it will return an error.
	icrud, err := singoton.Get[ICrud]()
	if err != nil {
		panic(err)
	}

	user := icrud.Read(1).(User) // Read return any, so we need to cast it to User.
	fmt.Println(user)

	// Similarly, we can use other method of ICrud interface. Create, Update, Delete.
}

The example above is a standard way to abstract CRUD operations. Required structs and interfaces. But for people who don't like to write interfaces, you can just register the struct right away.

// Not have to be a pointer. It also can be a value.
singoton.Register[&UserCrud{}]

And use it.

// Remember your data type. We register a pointer, so we get a pointer.
userCrud, _ := singoton.Get[*UserCrud]()

You can also overwrite or remove the object from dependency container.

package main

import "github.com/KafkaWannaFly/singoton"

func Overwrite() {
	// Overwrite the *UserCrud with a new one. Having 3 users inside.
	singoton.Register(&UserCrud{
		users: []User{
			{ID: 1, Name: "John"},
			{ID: 2, Name: "Jane"},
			{ID: 3, Name: "Jack"},
		},
	})
}

func Remove() {
	// Remove the *UserCrud from dependency container.
	// Notice that data type must be the same as the one you registered.
	singoton.UnRegister[*UserCrud]()
}

Register Object Factory

Sometimes you need to create a new object every time you get it. You can register a factory function to do that.

Step 1: Implement your factory.

// Package factory 
// StarFactory implements IFactory interface.
// It will create a new IStella every time you get it.
// Of course, it doesn't have to be an interface. It can be any data type.
package factory

import "math/rand"

type Star struct {
	size        int
	temperature int
}

type IStella interface {
	GetSize() int
	GetTemperature() int
}

func (s Star) GetSize() int {
	return s.size
}

func (s Star) GetTemperature() int {
	return s.temperature
}

type StarFactory struct {
}

func (sf StarFactory) New() IStella {
	return Star{
		size:        rand.Int(),
		temperature: rand.Int(),
	}
}

Step 2: Pretty much the same as above.

package main

import (
	"fmt"
	"github.com/KafkaWannaFly/singoton"
)

func registerFactory() {
	singoton.RegisterFactory[IStella](StarFactory{})
}

func getObjectFromFactory() {
	// Notice the data type. It's IStella.
	stella1, err1 := singoton.GetFromFactory[IStella]()
	if err1 != nil {
		panic(err1)
	}

	fmt.Println(stella1.GetSize())
	fmt.Println(stella1.GetTemperature())
}

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Get

func Get[T any]() (T, error)

Get an object of type T from dependency container. Return error if T was not registered.

Type T can be struct or interface. If T is an interface, it will return an implement of T. You must use the same type when register.

Example:

func main() {
	singoton.Register[IVehicle](new(Car))
	vehicle, _ := singoton.Get[IVehicle]()
	vehicle.Run()
}

func GetDependencyContainer

func GetDependencyContainer() *map[Metadata]any

GetDependencyContainer return a map of all registered objects.

func GetFromFactory

func GetFromFactory[T any]() (T, error)

GetFromFactory get an object of type T from factory. Return error if T was not registered.

Type T can be struct or interface. You must use the same type when register.

Example:

func main() {
	singoton.RegisterFactory[IStella](StarFactory{})
	star, _ := singoton.GetFromFactory[IStella]()
	star.GetSize()
	star.GetTemperature()
}

func GetInterfaceImplement

func GetInterfaceImplement() *map[Metadata]Metadata

GetInterfaceImplement return a map of all registered interface and it's implementation.

func IsRegistered

func IsRegistered[T any]() bool

IsRegistered check if an object of type T was registered to dependency container.

Type T can be struct or interface. Must be the same type when register.

Example:

func main() {
	singoton.Register[IVehicle](new(Car))
	singoton.IsRegistered[IVehicle]() // return true
	singoton.IsRegistered[Car]() // return true
	singoton.IsRegistered[Bus]() // return false
}

func Register

func Register[T any](object T)

Register an object of type T to dependency container Type T can be struct or interface Example:

	type IVehicle interface {
		Run()
	}

	type Car struct {}

	func (c *Car) Run() {}

	func main() {
    	// Register IVehicle interface, with Car implement, pointer of Car
		singoton.Register[IVehicle](new(Car))
		// Or you can just register Car, without interface
		singoton.Register(Car{...})
	}

func RegisterFactory

func RegisterFactory[T any](factory IFactory[T])

RegisterFactory register a factory of type T to dependency container.

Factory must implement IFactory[T] interface. Type T can be struct or interface.

Example:

type IStella interface {
	GetSize() int
	GetTemperature() int
}

type Star struct {
	size        int
	temperature int
}

func (s Star) GetSize() int {
	return s.size
}

func (s Star) GetTemperature() int {
	return s.temperature
}

type StarFactory struct {
}

func (sf StarFactory) New() IStella {
	return Star{
		size:        rand.Int(),
		temperature: rand.Int(),
	}
}

func main() {
	singoton.RegisterFactory[IStella](StarFactory{})
}

func UnRegister

func UnRegister[T any]()

UnRegister an object of type T from dependency container.

Type T can be struct or interface. Must be the same type when register.

Example:

func main() {
	singoton.Register[IVehicle](new(Car))
	singoton.UnRegister[IVehicle]()
}

func UnRegisterFactory

func UnRegisterFactory[T any]()

UnRegisterFactory unregister a factory of type T from dependency container.

Type T can be struct or interface. Must be the same type when register.

Types

type IFactory

type IFactory[T any] interface {
	// New return an object of type T
	New() T
}

IFactory is an interface for factory. You must implement this interface to use RegisterFactory.

Type T can be struct or interface.

type Metadata

type Metadata struct {
	Name    string `json:"name"`
	Package string `json:"package"`
}

Metadata is a struct to store type name and package name of a type

func (Metadata) ToString

func (metadata Metadata) ToString() string

ToString Return JSON string of Metadata

Directories

Path Synopsis
test
performance_test
trunk-ignore-all(golangci-lint)
trunk-ignore-all(golangci-lint)

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL