I want to select a specific repository at runtime by, for example, passing an argument to, let’s say, a “selector” function. Yes, it is something like a Strategy pattern in OOP. Say I have a “selector” function/struct/whatever you name it. When I call it by passing Account struct, I should only be able to access its methods so Total(). If I pass User then FindNameByID(id int). Is this possible with Go?
I looked at Go Strategy pattern but my structs will always have different functions in them.
Thanks
package repository
type User struct {
// Some field(s)
}
func (u User) FindNameByID(id int) string {
// Do something with u
users := map[int]string{1: "bob", 2: "jon"}
return users[id]
}
package repository
type Account struct {
// Some field(s)
}
func (a Account) Total() int {
// Do something with a
return 10
}
Usage
ar := RepoSelector(Account{})
ar->Total()
ur := RepoSelector(User{})
ur->FindNameByID(1)
NOTE: Somehow, if possible, I don’t want to pass field parameters to Account and User so they should be already injected.
If you use strategy pattern, you should define your method in your interface. let say your interface is
type RepoSelector interface { FindNameByID(int) Total() int }
So when you define method in your RepoSelector interface it must be accessible that two method FindNameByID(int) and Total() int in your struct. e.g for Account and User
type User struct {} func (u User) Total()int {} func (u User) FindNameByID(int){}
type Account struct {} func (a Account) Total()int {} func (a Account) FindNameByID(int){}
Thanks for the answer. However, your solution goes against my “only” requirement which isolates functions per receivers so if I fetch User, only FindNameByID() should be visible, not Total().
For me, It is impossible to isolate method with single interface. However, I just write a simple code to find a way to isolate functions using two interface.
type SelectorA interface {
FindNameByID(int)
}
type SelectorB interface {
Total() int
}
type Operation struct {}
func NewOperation(m interface{}) interface{} {`
switch v := m.(type) {
case SelectorA:
log.Println("[ SelectorA ]",v)
return v
case SelectorB:
log.Println("[ SelectorB ]",v)
return v
default:
log.Println("Unknown interface")
}
return nil
}
type User struct {}
func (a User) FindNameByID(n int) {
log.Println("user:",n)
}
type Account struct {}
func (a Account) Total() int {
return 10
}
func main() {
me := NewOperation(User{}).(User) // as User, since it is interface
me.FindNameByID(34)
n := NewOperation(Account{}).(Account)
log.Println("Total:",n.Total())
}
I’m a little confused by your example. It seems that when you get a User, you want to treat it as some sort of repository of Users that you can lookup by ID, but when you get an Account, you’re getting a Total of a specific account. Does User get you one specific User or a repository, and does Account get you one account or a repository?
Your solution is what I though at some point as well but as you probably already guessed it might get very ugly very quickly as things grow. I’ll probably rethink about my idea as so far I couldn’t find a clean solution. Thanks for the input though.