【问题标题】:Is it bad to use a struct and treat it like a class to solve the dependency in Golang?使用 struct 并将其视为类来解决 Golang 中的依赖关系是不是很糟糕?
【发布时间】:2017-05-16 10:46:17
【问题描述】:

我之前用OOP框架写了很多PHP,正在学习Golang,

当我使用 PHP 时,class 很有用,我可以将$model 传递给我的类,然后在函数之间共享它

class User {
   function __construct(UserModel $model) {
       $this->model = $model
   }

   function delete($id) {
       $this->model->delete($id);
   }

   function update($id) {
       $this->model->update($id);
   }
}

$UserModel = new UserModel();
$User      = new User($UserModel);
$User->delete(1);

但是在 Golang 中没有 class,我知道我可以将结构视为一个类:

type User struct {
    model *models.User
}

func (u *User) Delete(id int) {
    u.model.Delete(id)
}

func (u *User) Update(id int) {
    u.model.Update(id)
}

userModel := &models.User{}
user      := User{model: userModel}
user.Delete(1)

感觉struct用来存储信息的结构体的方法应该用来修改结构体的值

但是现在我做了一个结构,只是因为我想把它当作一个类解决依赖问题,在 Golang 中使用这种方法是不是很糟糕?

【问题讨论】:

  • 我不确定你到底在问什么,但我看不出你在做什么有什么问题(除了将 int 传递给这些函数而不是 id –它不会按原样编译)。
  • 糟糕,感谢您的纠正,就像我说的,我来自 OOP 背景,但我不确定是否应该将我的“旧想法”带到新语言中,因为我听说很多关于“不要在 Golang 中使用 OOP”,这就是为什么我不确定我这样做是对还是错。
  • 我认为反对在 Go 中使用 OOP 的警告是愚蠢的。显然,Go 不是典型的 C++ 或 Java 模型中的面向对象语言,但它确实具有允许您在开发软件时使用 OO 原则的特性。正如你所说,Go 没有传统的类,但它有结构、接口、带有接收器的方法和嵌入,所有这些都允许你做类似于你在 OO 语言中可以做的事情。一些值得注意的例外是没有构造函数和析构函数,并且没有直接等效的子类化(尽管嵌入是相似的)。
  • 我也不清楚你在问什么所以一些随机的想法:依赖注入是要走的路;您当然可以将结构定义视为一个类,并将该结构的实例视为对象;你可能想要一个func NewUser(m *models.User) User { ... }
  • @Plato 我之前考虑过使用func NewUser(m *models.User) User { ... },但我必须在我的函数周围传递models.User,另外,如果我想为函数添加新参数,它并不灵活。

标签: oop go struct dependency-injection dependencies


【解决方案1】:

从整体概念的角度来看,您的实现没有任何问题。

在详细视图中存在引起问题的不一致之处。

在以下所有情况下,由于各种 Delete 调用之间共享数据,都存在潜在的并发问题。

案例A

如果 models.User{} 完成了所有工作,那我们为什么不能这样做

userModel := &models.User{}
userModel.Delete(userId)

案例 B

如果 User 是我们的公共接口:

user      := User{model: userModel}
user.Delete(1)

然后删除 userId 是多余的,应该这样做:

user.Delete()

userId 取自用户上下文。

案例 C

否则,我们可能希望为所有用户实例设置 userModel:

package User;
// private package level variable
var model = userModel
func Delete(userId int) {
    model.Delete(userId)
}
...
User.Delete(userId)

结论

上述每个案例都解决了相同的问题,但重点略有不同。案例 A 很简单。案例 B 和 C 依赖于可与事件通知一起使用的底层共享代码。案例 B 和 C 在用户范围内是不同的。在案例 B 中,用户是一个结构。在案例 C 中,用户是包名称。我认为案例 C 的使用频率低于案例 B。因此,如果用户坚持有一个底层模型,那么从用户代码的角度来看,案例 B 可能是最直观的解决方案。

【讨论】:

    【解决方案2】:

    你可以使用接口和方法 服务中(连接数据库)

    // UserServiceInterface include method list
    type UserServiceInterface interface {
        GetAll(helpers.ParamsGetAll) (models.PublicUsers, error)
        Get(int64) (models.User, error)
        Delete(int64) (bool, error)
        Create(models.User) (int64, error)
        Update(models.User) (models.User, error)
        CheckExistUsername(string) (bool, error)
        CheckExistEmail(string) (bool, error)
        CreateEmailActive(string, string, int64) error
        CheckExistUser(int64) (bool, error)
    }
    
    // UserService struct
    type userService struct{}
    
    // NewUserService to constructor
    func NewUserService() userService {
        return userService{}
    }
    
    func (userService )GetAll (p helpers.ParamGetAll)(models.PublicUser, error) {
        code here....
    }
    

    在用户控制器中

    // UserController controller
    type UserController struct {
        Service services.UserServiceInterface
    }
        func (controller UserController) GetAll(c *gin.Context) {
        users, errGetAll := controller.Service.GetAll(params)
    }
    

    【讨论】:

      猜你喜欢
      • 2019-01-21
      • 2016-01-10
      • 2011-10-06
      • 1970-01-01
      • 2011-09-20
      • 1970-01-01
      • 2010-12-09
      • 2010-12-16
      • 1970-01-01
      相关资源
      最近更新 更多