Reputation: 673
I have a struct that two other objects implement. In this case, typeA and B repo's. There's some initialization code, which are represented as ellipses here. The initialization code is completely duplicated between both constructors, and isn't a big deal while I only have two dbRepo
's, but as I create more I will worry a bit more about the bad practice. Is there any way to generalize this with an interface?
type dbRepo struct {
foo string
bar string
}
type typeARepo dbRepo
type typeBRepo dbRepo
func newTypeARepo(foo, bar string) {
...
}
func newTypeBRepo(foo, bar string) {
...
}
Upvotes: 3
Views: 6221
Reputation: 99195
Define an unexported func on the type that does the initialization then you can create few constructors that call it, for example:
func (db *dbRepo) init(){
if len(db.foo) > 0 {
//do foo init
}
if len(db.bar) > 0 {
// do bar init
}
// do generic init
}
func NewRepo(foo, bar string) *dbRepo {
repo := &dbRepo{foo: foo, bar: bar}
repo.init()
return repo
}
func NewFooRepo(foo string) *dbRepo {
repo := &dbRepo{foo: foo}
repo.init()
return repo
}
Upvotes: 2
Reputation: 48076
The practice I've personally observed in Go (and it's also what's recommended in the effective Go or getting started with Go tutorials) is just to define a NewdbRepo
function and use it for all instantation. It's implementation would look something like;
func NewdbRepo(f, b string) *dbRepo {
return &dbRepo{ foo:f, bar:b}
}
You can't actually define a constructor as you do in most C like languages so you just gotta provide a package scoped method to do construction for you. Also, if you're not using composite literals (the initilization style I use in my NewdbRepo implementation) then you may find that alone concise enough for your needs.
Upvotes: 5
Reputation: 12239
You can write one function with your initializing code:
func newDbRepo(foo, bar string) dbRepo {
// ...
}
Then you can use it with type conversion:
a := typeARepo(newDbRepo("foo", "bar"))
b := typeBRepo(newDbRepo("foo", "bar"))
Upvotes: 2