使用接口(interface)可以避免在Go语言中出现代码重复的情况。

huangapple go评论88阅读模式
英文:

Avoid code duplication with interface in golang

问题

避免这种代码重复的惯用方法是使用接口和泛型。你可以创建一个通用的创建方法,接受一个接口类型作为参数,然后在方法内部使用类型断言来处理不同的对象。这样可以避免重复的代码。

以下是一个示例:

func Create(ctx context.Context, obj interface{}) (interface{}, error) {
  switch v := obj.(type) {
  case *Account:
    if ret, err := datastore.Put(ctx, v.newKey(ctx), v); err != nil {
      log.Errorf(ctx, "Error while creating Account: %v\n", err)
      return nil, err
    } else {
      v.Id = strconv.FormatInt(ret.IntID(), 10)
    }
    return v, nil
  case *Index:
    if ret, err := datastore.Put(ctx, v.newKey(ctx), v); err != nil {
      log.Errorf(ctx, "Error while creating Index: %v\n", err)
      return nil, err
    } else {
      v.Id = strconv.FormatInt(ret.IntID(), 10)
    }
    return v, nil
  default:
    return nil, errors.New("Unsupported type")
  }
}

通过将对象作为接口类型传递给通用的创建方法,你可以避免重复的代码,并根据对象的类型执行相应的操作。这样,你只需要编写一次创建方法,就可以处理不同类型的对象。

英文:

I am using the Google Cloud Datastore (or the google app engine datastore), to store different objects. Most of these objects are similar, hence I end up with lots of code duplication.

As an example, here are two create methods, of two different objects, account and index.

func (account *Account) Create(ctx context.Context) (*Account, error) {
  if ret, err := datastore.Put(ctx, account.newKey(ctx), account); err != nil {
    log.Errorf(ctx, "Error while creating Account : %v\n", err)
    return nil, err
  } else {
    account.Id = strconv.FormatInt(ret.IntID(), 10)
  }

  return account, nil
}

func (index *Index) Create(ctx context.Context) (*Index, error) { 
  if ret, err := datastore.Put(ctx, index.newKey(ctx), index); err != nil {
    log.Errorf(ctx, "Error while creating Index : %v\n", err)
    return nil, err
  } else {
    index.Id = strconv.FormatInt(ret.IntID(), 10)
  }

  return index, nil
}

As you can see, the two snippets are identical, excepts for the holder type, the return type, and the error message.

What is the idiomatic way to avoid this kind of code duplication ?

答案1

得分: 3

使用接口定义方法NewKey()SetID()

type Entity interface {
  SetId(id int64)
  NewKey(c context.Context) *datastore.Key
}

func create(c context.Context, entity Entity) error { 
  if ret, err := datastore.Put(c, entity.NewKey(c), entity ); err != nil {
    log.Errorf(c, "Error while creating entity: %v\n", err)
    return err
  } else {
    entity.SetId(ret.IntID())
    return nil
  }
}

func (index *Index) Create(c context.Context) (*Index, error) {
  return index, create(c, index)
}

func (account *Account) Create(c context.Context) (*Account, error) {
  return account, create(c, account)
}
英文:

Use interface to define methods NewKey() & SetID()

type Entity interface {
  SetId(id int64)
  NewKey(c context.Context) *datastore.Key
}

func create(c context.Context, entity Entity) error { 
  if ret, err := datastore.Put(c, entity.NewKey(c), entity ); err != nil {
    log.Errorf(c, "Error while creating entity: %v\n", err)
    return err
  } else {
    entity.SetId(ret.IntID())
    return nil
  }
}

func (index *Index) Create(c context.Context) (*Index, error) {
  return index, create(c, index)
}

func (account *Account) Create(c context.Context) (*Account, error) {
  return account, create(c, account)
}

huangapple
  • 本文由 发表于 2016年9月27日 16:51:30
  • 转载请务必保留本文链接:https://go.coder-hub.com/39720221.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定