creational

package
v0.10.102 Latest Latest
Warning

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

Go to latest
Published: Jul 28, 2026 License: MIT Imports: 2 Imported by: 0

README

Creational toolset

Functional options generic toolset to get rid of bloilerplate constructor functions.

// component.go

import (
	"go.uber.org/zap"

	c "github.com/agurinov/gopl/patterns/creational"
)

type (
	MyComponent struct {
		logger *zap.Logger
		s      string
		i      int
	}

	// Or it can alias as: MyComponentOption = c.Option[Closer]
	MyComponentOption c.Option[Closer]


	// Or it can alias as: MyCtxComponentOption = c.OptionWithContext[Closer]
	MyCtxComponentOption c.OptionWithContext[Closer]
)

var (
	// Creating new oject with values from provided options.
	New = c.New[MyComponent, MyComponentOption]

	// Creating and validating resulting object.
	// Object must have .Valdate() method.
	New = c.NewWithValidate[MyComponent, MyComponentOption]

	// Creating new oject with available context to create some socket.
	New = c.NewWithContext[MyComponent, MyCtxComponentOption]

	// Creating and validating new oject with available context to create some socket.
	// Object must have .Valdate() method.
	New = c.NewWithContextValidate[MyComponent, MyCtxComponentOption]
)

// Also there are pair of methods Construct* which can patch already existing object.
// Useful in case of known default state.
// Feel free to combine ctx and validate mechanics as you want.
func New(opts ...MyComponentOption) (*MyComponent, error) {
	c := MyComponent{
		s: "foobar",
		i: 100500,
	}

	obj, err := c.ConstructWithValidate(c, opts...)
	if err != nil {
		return nil, err
	}

	return &obj, nil
}
// component_f_opt.go

import (
	"go.uber.org/zap"
)

func WithLogger(logger *zap.Logger) MyComponentOption {
	return func(c *MyComponent) error {
		if logger == nil {
			return nil
		}

		c.logger = logger.Named("my.component")

		return nil
	}
}

func WithContextLogger(logger *zap.Logger) MyComponentOption {
	return func(ctx context.Context, c *MyComponent) error {
		if logger == nil {
			return nil
		}

		c.logger = logger.Named("my.component")

		return nil
	}
}

Documentation

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func Construct

func Construct[
	O Object,
	FO Option[O] | optionAlias[O],
](
	obj O,
	opts ...FO,
) (O, error)

func ConstructWithContext

func ConstructWithContext[
	O Object,
	FO OptionWithContext[O] | optionWithContextAlias[O],
](
	ctx context.Context,
	obj O,
	opts ...FO,
) (O, error)

func ConstructWithContextValidate added in v0.3.0

func ConstructWithContextValidate[
	O ObjectValidable,
	FO OptionWithContext[O] | optionWithContextAlias[O],
](
	ctx context.Context,
	obj O,
	opts ...FO,
) (O, error)

func ConstructWithValidate added in v0.3.0

func ConstructWithValidate[
	O ObjectValidable,
	FO Option[O] | optionAlias[O],
](
	obj O,
	opts ...FO,
) (O, error)

func Must added in v0.8.0

func Must[T any](t T, err error) T

func MustDuo added in v0.8.81

func MustDuo[T1 any, T2 any](t1 T1, t2 T2, err error) (T1, T2)

func MustInit added in v0.8.66

func MustInit(err error)

func MustNew

func MustNew[
	O Object,
	FO Option[O] | optionAlias[O],
](
	opts ...FO,
) O

func New

func New[
	O Object,
	FO Option[O] | optionAlias[O],
](
	opts ...FO,
) (O, error)
Example

ExampleNew just configures object - no validate applied

package main

import (
	"fmt"
	"io"
	"strconv"
	"strings"

	"github.com/go-playground/validator/v10"

	c "github.com/agurinov/gopl/patterns/creational"
)

type (
	Worker struct {
		w io.ReadWriter
		s string
		i int
	}
	WorkerOption            c.Option[Worker]
	WorkerOptionWithContext = c.OptionWithContext[Worker]
)

var New = c.New[Worker, WorkerOption]

var (
	invalidW io.ReadWriter = nil
	invalidS               = "lolkek"
	invalidI               = 999
)

func (obj Worker) String() string {
	var b strings.Builder

	b.WriteString("s=" + obj.s + ";")
	b.WriteString("i=" + strconv.Itoa(obj.i) + ";")
	b.WriteString("w_is_nil=" + strconv.FormatBool(obj.w == nil) + ";")
	b.WriteString("is_valid=" + strconv.FormatBool(obj.Validate() == nil) + ";")

	return b.String()
}

func (obj Worker) Validate() error {
	s := struct {
		W io.ReadWriter `validate:"required"`
		S string        `validate:"eq=foobar"`
		I int           `validate:"eq=100500"`
	}{
		W: obj.w,
		S: obj.s,
		I: obj.i,
	}

	if err := validator.New().Struct(s); err != nil {
		return err
	}

	return nil
}

func main() {
	opts := []WorkerOption{
		WithW(invalidW), nil,
		WithS(invalidS), nil,
		WithI(invalidI), nil,
	}

	obj, err := New(opts...)
	if err != nil {
		panic(err)
	}

	fmt.Printf("%s\n", obj)
}

func WithI(i int) WorkerOption {
	return func(o *Worker) error {
		o.i = i

		return nil
	}
}

func WithS(s string) WorkerOption {
	return func(o *Worker) error {
		o.s = s

		return nil
	}
}

func WithW(w io.ReadWriter) WorkerOption {
	return func(o *Worker) error {
		o.w = w

		return nil
	}
}
Output:
s=lolkek;i=999;w_is_nil=true;is_valid=false;

func NewWithContext

func NewWithContext[
	O Object,
	FO OptionWithContext[O] | optionWithContextAlias[O],
](
	ctx context.Context,
	opts ...FO,
) (O, error)
Example

ExampleNewWithContext just configures object - no validate applied. Also ctx is required For example - http.Request as struct attribute

package main

import (
	"context"
	"fmt"
	"io"
	"strconv"
	"strings"

	"github.com/go-playground/validator/v10"

	c "github.com/agurinov/gopl/patterns/creational"
)

type (
	Worker struct {
		w io.ReadWriter
		s string
		i int
	}
	WorkerOption            c.Option[Worker]
	WorkerOptionWithContext = c.OptionWithContext[Worker]
)

var NewWithContext = c.NewWithContext[Worker, WorkerOptionWithContext]

var (
	invalidW io.ReadWriter = nil
	invalidS               = "lolkek"
	invalidI               = 999
)

func (obj Worker) String() string {
	var b strings.Builder

	b.WriteString("s=" + obj.s + ";")
	b.WriteString("i=" + strconv.Itoa(obj.i) + ";")
	b.WriteString("w_is_nil=" + strconv.FormatBool(obj.w == nil) + ";")
	b.WriteString("is_valid=" + strconv.FormatBool(obj.Validate() == nil) + ";")

	return b.String()
}

func (obj Worker) Validate() error {
	s := struct {
		W io.ReadWriter `validate:"required"`
		S string        `validate:"eq=foobar"`
		I int           `validate:"eq=100500"`
	}{
		W: obj.w,
		S: obj.s,
		I: obj.i,
	}

	if err := validator.New().Struct(s); err != nil {
		return err
	}

	return nil
}

func main() {
	ctx := context.TODO()

	opts := []WorkerOptionWithContext{
		WithWCtx(invalidW), nil,
		WithSCtx(invalidS), nil,
		WithICtx(invalidI), nil,
	}

	obj, err := NewWithContext(ctx, opts...)
	if err != nil {
		panic(err)
	}

	fmt.Printf("%s\n", obj)
}

func WithICtx(i int) WorkerOptionWithContext {
	return func(_ context.Context, o *Worker) error {
		o.i = i

		return nil
	}
}

func WithSCtx(s string) WorkerOptionWithContext {
	return func(_ context.Context, o *Worker) error {
		o.s = s

		return nil
	}
}

func WithWCtx(w io.ReadWriter) WorkerOptionWithContext {
	return func(_ context.Context, o *Worker) error {
		o.w = w

		return nil
	}
}
Output:
s=lolkek;i=999;w_is_nil=true;is_valid=false;

func NewWithContextValidate added in v0.3.0

func NewWithContextValidate[
	O ObjectValidable,
	FO OptionWithContext[O] | optionWithContextAlias[O],
](
	ctx context.Context,
	opts ...FO,
) (O, error)
Example

ExampleNewWithContextValidate configures and validates object. Also ctx is required For example - http.Request as struct attribute

package main

import (
	"bytes"
	"context"
	"fmt"
	"io"
	"strconv"
	"strings"

	"github.com/go-playground/validator/v10"

	c "github.com/agurinov/gopl/patterns/creational"
)

type (
	Worker struct {
		w io.ReadWriter
		s string
		i int
	}
	WorkerOption            c.Option[Worker]
	WorkerOptionWithContext = c.OptionWithContext[Worker]
)

var NewWithContextValidate = c.NewWithContextValidate[Worker, WorkerOptionWithContext]

var (
	validW io.ReadWriter = new(bytes.Buffer)
	validS               = "foobar"
	validI               = 100500
)

func (obj Worker) String() string {
	var b strings.Builder

	b.WriteString("s=" + obj.s + ";")
	b.WriteString("i=" + strconv.Itoa(obj.i) + ";")
	b.WriteString("w_is_nil=" + strconv.FormatBool(obj.w == nil) + ";")
	b.WriteString("is_valid=" + strconv.FormatBool(obj.Validate() == nil) + ";")

	return b.String()
}

func (obj Worker) Validate() error {
	s := struct {
		W io.ReadWriter `validate:"required"`
		S string        `validate:"eq=foobar"`
		I int           `validate:"eq=100500"`
	}{
		W: obj.w,
		S: obj.s,
		I: obj.i,
	}

	if err := validator.New().Struct(s); err != nil {
		return err
	}

	return nil
}

func main() {
	ctx := context.TODO()

	opts := []WorkerOptionWithContext{
		WithWCtx(validW), nil,
		WithSCtx(validS), nil,
		WithICtx(validI), nil,
	}

	obj, err := NewWithContextValidate(ctx, opts...)
	if err != nil {
		panic(err)
	}

	fmt.Printf("%s\n", obj)
}

func WithICtx(i int) WorkerOptionWithContext {
	return func(_ context.Context, o *Worker) error {
		o.i = i

		return nil
	}
}

func WithSCtx(s string) WorkerOptionWithContext {
	return func(_ context.Context, o *Worker) error {
		o.s = s

		return nil
	}
}

func WithWCtx(w io.ReadWriter) WorkerOptionWithContext {
	return func(_ context.Context, o *Worker) error {
		o.w = w

		return nil
	}
}
Output:
s=foobar;i=100500;w_is_nil=false;is_valid=true;

func NewWithValidate added in v0.3.0

func NewWithValidate[
	O ObjectValidable,
	FO Option[O] | optionAlias[O],
](
	opts ...FO,
) (O, error)
Example

ExampleNewWithValidate configures and validates object

package main

import (
	"bytes"
	"fmt"
	"io"
	"strconv"
	"strings"

	"github.com/go-playground/validator/v10"

	c "github.com/agurinov/gopl/patterns/creational"
)

type (
	Worker struct {
		w io.ReadWriter
		s string
		i int
	}
	WorkerOption            c.Option[Worker]
	WorkerOptionWithContext = c.OptionWithContext[Worker]
)

var NewWithValidate = c.NewWithValidate[Worker, WorkerOption]

var (
	validW io.ReadWriter = new(bytes.Buffer)
	validS               = "foobar"
	validI               = 100500
)

func (obj Worker) String() string {
	var b strings.Builder

	b.WriteString("s=" + obj.s + ";")
	b.WriteString("i=" + strconv.Itoa(obj.i) + ";")
	b.WriteString("w_is_nil=" + strconv.FormatBool(obj.w == nil) + ";")
	b.WriteString("is_valid=" + strconv.FormatBool(obj.Validate() == nil) + ";")

	return b.String()
}

func (obj Worker) Validate() error {
	s := struct {
		W io.ReadWriter `validate:"required"`
		S string        `validate:"eq=foobar"`
		I int           `validate:"eq=100500"`
	}{
		W: obj.w,
		S: obj.s,
		I: obj.i,
	}

	if err := validator.New().Struct(s); err != nil {
		return err
	}

	return nil
}

func main() {
	opts := []WorkerOption{
		WithW(validW), nil,
		WithS(validS), nil,
		WithI(validI), nil,
	}

	obj, err := NewWithValidate(opts...)
	if err != nil {
		panic(err)
	}

	fmt.Printf("%s\n", obj)
}

func WithI(i int) WorkerOption {
	return func(o *Worker) error {
		o.i = i

		return nil
	}
}

func WithS(s string) WorkerOption {
	return func(o *Worker) error {
		o.s = s

		return nil
	}
}

func WithW(w io.ReadWriter) WorkerOption {
	return func(o *Worker) error {
		o.w = w

		return nil
	}
}
Output:
s=foobar;i=100500;w_is_nil=false;is_valid=true;

Types

type Fabric added in v0.10.76

type Fabric[
	O Object,
	FO Option[O] | optionAlias[O],
] []FO
Example

ExampleFabric configures fabric with defaults. Also, fabric can be overrided with runtime specific options.

package main

import (
	"bytes"
	"fmt"
	"io"
	"strconv"
	"strings"

	"github.com/go-playground/validator/v10"

	c "github.com/agurinov/gopl/patterns/creational"
)

type (
	Worker struct {
		w io.ReadWriter
		s string
		i int
	}
	WorkerOption            c.Option[Worker]
	WorkerOptionWithContext = c.OptionWithContext[Worker]
)

type WorkerFabric = c.Fabric[Worker, WorkerOption]

var (
	validW io.ReadWriter = new(bytes.Buffer)
	validS               = "foobar"
	validI               = 100500
)

func (obj Worker) String() string {
	var b strings.Builder

	b.WriteString("s=" + obj.s + ";")
	b.WriteString("i=" + strconv.Itoa(obj.i) + ";")
	b.WriteString("w_is_nil=" + strconv.FormatBool(obj.w == nil) + ";")
	b.WriteString("is_valid=" + strconv.FormatBool(obj.Validate() == nil) + ";")

	return b.String()
}

func (obj Worker) Validate() error {
	s := struct {
		W io.ReadWriter `validate:"required"`
		S string        `validate:"eq=foobar"`
		I int           `validate:"eq=100500"`
	}{
		W: obj.w,
		S: obj.s,
		I: obj.i,
	}

	if err := validator.New().Struct(s); err != nil {
		return err
	}

	return nil
}

func main() {
	var fabric WorkerFabric = []WorkerOption{
		WithW(validW), nil,
		WithS(validS), nil,
		WithI(validI), nil,
	}

	obj, err := fabric.New(
		WithI(112233), nil,
	)
	if err != nil {
		panic(err)
	}

	fmt.Printf("%s\n", obj)
}

func WithI(i int) WorkerOption {
	return func(o *Worker) error {
		o.i = i

		return nil
	}
}

func WithS(s string) WorkerOption {
	return func(o *Worker) error {
		o.s = s

		return nil
	}
}

func WithW(w io.ReadWriter) WorkerOption {
	return func(o *Worker) error {
		o.w = w

		return nil
	}
}
Output:
s=foobar;i=112233;w_is_nil=false;is_valid=false;

func (Fabric[O, FO]) New added in v0.10.76

func (f Fabric[O, FO]) New(opts ...FO) (O, error)

type FabricWithContext added in v0.10.76

type FabricWithContext[
	O Object,
	FO OptionWithContext[O] | optionWithContextAlias[O],
] []FO
Example

ExampleFabricWithContext configures fabric with defaults. Also, fabric can be overrided with runtime specific options.

package main

import (
	"context"
	"fmt"
	"io"
	"strconv"
	"strings"

	"github.com/go-playground/validator/v10"

	c "github.com/agurinov/gopl/patterns/creational"
)

type (
	Worker struct {
		w io.ReadWriter
		s string
		i int
	}
	WorkerOption            c.Option[Worker]
	WorkerOptionWithContext = c.OptionWithContext[Worker]
)

type WorkerFabricWithContext = c.FabricWithContext[Worker, WorkerOptionWithContext]

var (
	invalidW io.ReadWriter = nil
	invalidS               = "lolkek"
	invalidI               = 999
)

func (obj Worker) String() string {
	var b strings.Builder

	b.WriteString("s=" + obj.s + ";")
	b.WriteString("i=" + strconv.Itoa(obj.i) + ";")
	b.WriteString("w_is_nil=" + strconv.FormatBool(obj.w == nil) + ";")
	b.WriteString("is_valid=" + strconv.FormatBool(obj.Validate() == nil) + ";")

	return b.String()
}

func (obj Worker) Validate() error {
	s := struct {
		W io.ReadWriter `validate:"required"`
		S string        `validate:"eq=foobar"`
		I int           `validate:"eq=100500"`
	}{
		W: obj.w,
		S: obj.s,
		I: obj.i,
	}

	if err := validator.New().Struct(s); err != nil {
		return err
	}

	return nil
}

func main() {
	ctx := context.TODO()

	var fabric WorkerFabricWithContext = []WorkerOptionWithContext{
		WithWCtx(invalidW), nil,
		WithSCtx(invalidS), nil,
		WithICtx(112233), nil,
	}

	obj, err := fabric.New(
		ctx,
		WithICtx(invalidI), nil,
	)
	if err != nil {
		panic(err)
	}

	fmt.Printf("%s\n", obj)
}

func WithICtx(i int) WorkerOptionWithContext {
	return func(_ context.Context, o *Worker) error {
		o.i = i

		return nil
	}
}

func WithSCtx(s string) WorkerOptionWithContext {
	return func(_ context.Context, o *Worker) error {
		o.s = s

		return nil
	}
}

func WithWCtx(w io.ReadWriter) WorkerOptionWithContext {
	return func(_ context.Context, o *Worker) error {
		o.w = w

		return nil
	}
}
Output:
s=lolkek;i=999;w_is_nil=true;is_valid=false;

func (FabricWithContext[O, FO]) New added in v0.10.76

func (f FabricWithContext[O, FO]) New(ctx context.Context, opts ...FO) (O, error)

type FabricWithContextValidate added in v0.10.76

type FabricWithContextValidate[
	O ObjectValidable,
	FO OptionWithContext[O] | optionWithContextAlias[O],
] []FO
Example

ExampleFabricWithContextValidate configures fabric with defaults. Also, fabric can be overrided with runtime specific options.

package main

import (
	"bytes"
	"context"
	"fmt"
	"io"
	"strconv"
	"strings"

	"github.com/go-playground/validator/v10"

	c "github.com/agurinov/gopl/patterns/creational"
)

type (
	Worker struct {
		w io.ReadWriter
		s string
		i int
	}
	WorkerOption            c.Option[Worker]
	WorkerOptionWithContext = c.OptionWithContext[Worker]
)

type WorkerFabricWithContextValidate = c.FabricWithContextValidate[Worker, WorkerOptionWithContext]

var (
	validW io.ReadWriter = new(bytes.Buffer)
	validS               = "foobar"
	validI               = 100500
)

func (obj Worker) String() string {
	var b strings.Builder

	b.WriteString("s=" + obj.s + ";")
	b.WriteString("i=" + strconv.Itoa(obj.i) + ";")
	b.WriteString("w_is_nil=" + strconv.FormatBool(obj.w == nil) + ";")
	b.WriteString("is_valid=" + strconv.FormatBool(obj.Validate() == nil) + ";")

	return b.String()
}

func (obj Worker) Validate() error {
	s := struct {
		W io.ReadWriter `validate:"required"`
		S string        `validate:"eq=foobar"`
		I int           `validate:"eq=100500"`
	}{
		W: obj.w,
		S: obj.s,
		I: obj.i,
	}

	if err := validator.New().Struct(s); err != nil {
		return err
	}

	return nil
}

func main() {
	ctx := context.TODO()

	var fabric WorkerFabricWithContextValidate = []WorkerOptionWithContext{
		WithWCtx(validW), nil,
		WithSCtx(validS), nil,
		WithICtx(112233), nil,
	}

	obj, err := fabric.New(
		ctx,
		WithICtx(validI), nil,
	)
	if err != nil {
		panic(err)
	}

	fmt.Printf("%s\n", obj)
}

func WithICtx(i int) WorkerOptionWithContext {
	return func(_ context.Context, o *Worker) error {
		o.i = i

		return nil
	}
}

func WithSCtx(s string) WorkerOptionWithContext {
	return func(_ context.Context, o *Worker) error {
		o.s = s

		return nil
	}
}

func WithWCtx(w io.ReadWriter) WorkerOptionWithContext {
	return func(_ context.Context, o *Worker) error {
		o.w = w

		return nil
	}
}
Output:
s=foobar;i=100500;w_is_nil=false;is_valid=true;

func (FabricWithContextValidate[O, FO]) New added in v0.10.76

func (f FabricWithContextValidate[O, FO]) New(ctx context.Context, opts ...FO) (O, error)

type FabricWithValidate added in v0.10.76

type FabricWithValidate[
	O ObjectValidable,
	FO Option[O] | optionAlias[O],
] []FO
Example

ExampleFabricWithValidate configures fabric with defaults. Also, fabric can be overrided with runtime specific options.

package main

import (
	"bytes"
	"fmt"
	"io"
	"strconv"
	"strings"

	"github.com/go-playground/validator/v10"

	c "github.com/agurinov/gopl/patterns/creational"
)

type (
	Worker struct {
		w io.ReadWriter
		s string
		i int
	}
	WorkerOption            c.Option[Worker]
	WorkerOptionWithContext = c.OptionWithContext[Worker]
)

type WorkerFabricWithValidate = c.FabricWithValidate[Worker, WorkerOption]

var (
	validW io.ReadWriter = new(bytes.Buffer)
	validS               = "foobar"
	validI               = 100500
)

func (obj Worker) String() string {
	var b strings.Builder

	b.WriteString("s=" + obj.s + ";")
	b.WriteString("i=" + strconv.Itoa(obj.i) + ";")
	b.WriteString("w_is_nil=" + strconv.FormatBool(obj.w == nil) + ";")
	b.WriteString("is_valid=" + strconv.FormatBool(obj.Validate() == nil) + ";")

	return b.String()
}

func (obj Worker) Validate() error {
	s := struct {
		W io.ReadWriter `validate:"required"`
		S string        `validate:"eq=foobar"`
		I int           `validate:"eq=100500"`
	}{
		W: obj.w,
		S: obj.s,
		I: obj.i,
	}

	if err := validator.New().Struct(s); err != nil {
		return err
	}

	return nil
}

func main() {
	var fabric WorkerFabricWithValidate = []WorkerOption{
		WithW(validW), nil,
		WithS(validS), nil,
		WithI(112233), nil,
	}

	obj, err := fabric.New(
		WithI(validI), nil,
	)
	if err != nil {
		panic(err)
	}

	fmt.Printf("%s\n", obj)
}

func WithI(i int) WorkerOption {
	return func(o *Worker) error {
		o.i = i

		return nil
	}
}

func WithS(s string) WorkerOption {
	return func(o *Worker) error {
		o.s = s

		return nil
	}
}

func WithW(w io.ReadWriter) WorkerOption {
	return func(o *Worker) error {
		o.w = w

		return nil
	}
}
Output:
s=foobar;i=100500;w_is_nil=false;is_valid=true;

func (FabricWithValidate[O, FO]) New added in v0.10.76

func (f FabricWithValidate[O, FO]) New(opts ...FO) (O, error)

type Object

type Object interface{ any }

type ObjectValidable added in v0.3.0

type ObjectValidable interface{ Validate() error }

type Option

type Option[O Object] func(*O) error

type OptionWithContext

type OptionWithContext[O Object] func(context.Context, *O) error

Jump to

Keyboard shortcuts

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