Golang中如何根据参数选择特定功能

Golang中如何根据参数选择特定功能 你好,

我希望在运行时通过向一个“选择器”函数传递参数来选择特定的存储库。是的,这类似于面向对象编程中的策略模式。假设我有一个“选择器”函数/结构体,或者随便你怎么称呼它。当我传递 Account 结构体调用它时,我应该只能访问其方法,例如 Total()。如果我传递 User,则只能访问 FindNameByID(id int)。这在 Go 语言中可以实现吗?

我查看了 Go 策略模式,但我的结构体内部总是会有不同的函数。

谢谢

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
}

用法

ar := RepoSelector(Account{})
ar->Total()

ur := RepoSelector(User{})
ur->FindNameByID(1)

注意:如果可能的话,我希望不向 AccountUser 传递字段参数,因此它们应该已经被注入。


更多关于Golang中如何根据参数选择特定功能的实战教程也可以访问 https://www.itying.com/category-94-b0.html

7 回复

@skillian 你误解了重点,纠结于函数可能做什么,这与问题本身无关。

更多关于Golang中如何根据参数选择特定功能的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


感谢您的回答。然而,您的解决方案违背了我“唯一”的要求,即按接收者隔离函数,因此如果我获取 User,应该只看到 FindNameByID(),而不是 Total()

谢谢 @adriel

你的解决方案也是我某个时刻想到过的,但你可能已经猜到,随着事情发展,它可能会很快变得非常混乱。我可能会重新考虑我的想法,因为到目前为止我还没有找到一个清晰的解决方案。不过还是谢谢你的建议。

@GoingToGo

我对你的示例有些困惑。看起来,当你获取一个 User 时,你希望将其视为某种可以通过 ID 查找的 User 存储库,但当你获取一个 Account 时,你得到的是一个特定账户的 Total。那么,User 是获取一个特定的 User 还是一个存储库?Account 是获取一个账户还是一个存储库?

你好 @GoingToGo

如果你使用策略模式,你应该在你的接口中定义你的方法。假设你的接口是:

type RepoSelector interface {
FindNameByID(int)
Total() int
}

因此,当你在 RepoSelector 接口中定义方法时,你的结构体必须能够访问这两个方法 FindNameByID(int)Total() int。例如,对于 AccountUser

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){}

对我来说,使用单一接口来隔离方法是不可能的。不过,我写了一段简单的代码,尝试通过两个接口来隔离函数。

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) // 作为 User 类型,因为它是接口
    me.FindNameByID(34)

    n := NewOperation(Account{}).(Account)
    log.Println("Total:",n.Total())
}

在Go中可以通过接口和类型断言实现运行时根据参数选择特定功能。以下是几种实现方式:

方法一:使用接口和类型断言

package main

import "fmt"

// 定义接口
type Repository interface{}

// 具体类型
type User struct{}

func (u User) FindNameByID(id int) string {
    users := map[int]string{1: "bob", 2: "jon"}
    return users[id]
}

type Account struct{}

func (a Account) Total() int {
    return 10
}

// 选择器函数
func RepoSelector(repo Repository) interface{} {
    return repo
}

func main() {
    // 使用类型断言调用特定方法
    ar := RepoSelector(Account{})
    if acc, ok := ar.(Account); ok {
        fmt.Println("Account Total:", acc.Total())
    }

    ur := RepoSelector(User{})
    if user, ok := ur.(User); ok {
        fmt.Println("User Name:", user.FindNameByID(1))
    }
}

方法二:使用函数返回具体类型

package main

import "fmt"

type User struct{}

func (u User) FindNameByID(id int) string {
    users := map[int]string{1: "bob", 2: "jon"}
    return users[id]
}

type Account struct{}

func (a Account) Total() int {
    return 10
}

// 选择器函数返回具体类型
func RepoSelector(repo interface{}) interface{} {
    return repo
}

// 包装函数提供类型安全调用
func UseAccount() {
    ar := RepoSelector(Account{}).(Account)
    fmt.Println("Account Total:", ar.Total())
}

func UseUser() {
    ur := RepoSelector(User{}).(User)
    fmt.Println("User Name:", ur.FindNameByID(1))
}

func main() {
    UseAccount()
    UseUser()
}

方法三:使用泛型(Go 1.18+)

package main

import "fmt"

type User struct{}

func (u User) FindNameByID(id int) string {
    users := map[int]string{1: "bob", 2: "jon"}
    return users[id]
}

type Account struct{}

func (a Account) Total() int {
    return 10
}

// 泛型选择器
func RepoSelector[T any](repo T) T {
    return repo
}

func main() {
    // 类型安全的调用
    ar := RepoSelector(Account{})
    fmt.Println("Account Total:", ar.Total())

    ur := RepoSelector(User{})
    fmt.Println("User Name:", ur.FindNameByID(1))
}

方法四:工厂模式实现

package main

import "fmt"

type Repository interface {
    Execute() interface{}
}

type User struct{}

func (u User) FindNameByID(id int) string {
    users := map[int]string{1: "bob", 2: "jon"}
    return users[id]
}

func (u User) Execute() interface{} {
    return u.FindNameByID(1)
}

type Account struct{}

func (a Account) Total() int {
    return 10
}

func (a Account) Execute() interface{} {
    return a.Total()
}

// 工厂函数
func RepoSelector(repo Repository) interface{} {
    return repo.Execute()
}

func main() {
    ar := RepoSelector(Account{})
    fmt.Println("Account Total:", ar)

    ur := RepoSelector(User{})
    fmt.Println("User Name:", ur)
}

方法五:使用闭包和函数类型

package main

import "fmt"

type User struct{}

func (u User) FindNameByID(id int) string {
    users := map[int]string{1: "bob", 2: "jon"}
    return users[id]
}

type Account struct{}

func (a Account) Total() int {
    return 10
}

// 定义函数类型
type RepoFunc func() interface{}

// 选择器返回闭包
func RepoSelector(repo interface{}) RepoFunc {
    switch r := repo.(type) {
    case Account:
        return func() interface{} {
            return r.Total()
        }
    case User:
        return func() interface{} {
            return r.FindNameByID(1)
        }
    default:
        return func() interface{} {
            return nil
        }
    }
}

func main() {
    ar := RepoSelector(Account{})
    fmt.Println("Account Total:", ar())

    ur := RepoSelector(User{})
    fmt.Println("User Name:", ur())
}

推荐使用方法三的泛型实现,它提供了类型安全且简洁的语法。如果使用Go 1.18之前的版本,方法一的类型断言是常用方式。

回到顶部