Tuesday, April 22, 2025
HomeGolangMove frequent object to nested structs - Code Assessment

Move frequent object to nested structs – Code Assessment


Hello,

I’d contemplate Useful Choices Sample. On the optimistic, it permits condensing a number of constructors right into a single one, with risk of extending it later, with out breaking consumer code, and gives shoppers with smart defaults (globalLogger in your instance). Draw back is that the code appears a bit troublesome, till you get the cling of it.

First it is advisable add two choices structs for every of your structs, which comprise all defaultable choices

sort FooOptions struct {
	logger Logger
}
...
sort BarOptions struct {
	logger Logger
	Foo    *Foo
}

Then, maintain solely NewFoo and NewBar constructors as follows

// Params earlier than choices - 'a' on this case, 
//these with out which service can't work,
// and also you, as implementor, can't know defaults for 
// (for instance, an API Key)
// choices - for params that may be defaulted (like Logger)
func NewFoo(a int, choices ...func(*FooOptions)) *Foo {
	// outline defaults
	ops := &FooOptions{}
	ops.logger = globalLogger

	// overwrite configuration with offered choices
	for _, possibility := vary choices {
		possibility(ops)
	}

	// configure Foo primarily based on ultimate set of choices
	return &Foo{a: a, logger: ops.logger}
}

... 

func NewBar(a int, b bool, choices ...func(*BarOptions)) *Bar {
	// outline defaults
	ops := &BarOptions{}
	ops.logger = globalLogger
	ops.Foo = NewFoo(a) // Foo With Default Logger

	// overwrite configuration with offered choices
	for _, possibility := vary choices {
		possibility(ops)
	}

	// configure Foo primarily based on ultimate set of choices
	return &Bar{b: b, logger: ops.logger, foo: ops.Foo}
}

Now, you’ll be able to outline choices funcs as follows, for comfort

func FooWithLogger(logger Logger) func(*FooOptions) {
	return func(ops *FooOptions) {
		ops.logger = logger
	}
}

...
func BarWithLogger(logger Logger) func(*BarOptions) {
	return func(ops *BarOptions) {
		ops.logger = logger
	}
}

func BarWithFoo(foo *Foo) func(*BarOptions) {
	return func(ops *BarOptions) {
		ops.Foo = foo
	}
}

And now your consumer can use it like proven beneath

func major() {
	// now you'll be able to both have bar with default logger, and default Foo
	_ = NewBar(2, true)

	// or present every little thing 
	_ = NewBar(2, false, BarWithLogger(Logger{}), BarWithFoo(NewFoo(3, FooWithLogger(Logger{}))))
}

Hope this helps

RELATED ARTICLES

LEAVE A REPLY

Please enter your comment!
Please enter your name here

Most Popular

Recent Comments