Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Subtypes Supertypes in go

Tags:

go

Coming from OOP paradigms and porting a code from an OOP language, I come across a problem now which is solved in OOP via abstraction so I'm wondering how can I approach the following problem in Go which follows composition instead of inheritance.

In this scenario my ValueObjects (DTO, POJO etc.) are composed of other ValueObjects. I'm populating them through web service calls that returns json so basically my functions/method calls are common for all types and subtypes.

My super type EntityVO

type EntityVO struct {
    EntityName    string
    EntityType    string
    PublicationId string
    Version       string
}

A subtype 1 composed with EntityVO

type ArticleVO struct {
    EntityVO
    ContentSize string
    Created     string
}

subtype 2 composed with EntityVO with it's own unique set of fields

type CollectionVO struct {
    EntityVO
    ProductId string
    Position string
}

I'm calling web services to retrieve data and populate these VOs.

Earlier I had one function to call the web service and populate the data but now I'm duplicating the code for each VO.

type Article struct{}

func (a *Article) RequestList(articleVO *valueObject.ArticleVO) (*valueObject.ArticleVO, error) { 
    // some code
}

Duplicating the same code but changing the signature.

type Collection struct{}

func (c * Collection) RequestList(collectionVO *valueObject.CollectionVO) (*valueObject.ArticleVO, error) { 
    // some code - duplicate same as above except method signature
}

and I've several entities and just because my VO's are different I'm forced to duplicate the code and cater to each type of VO I've. In OOP sub types can be passed to a function accepting super types but not in go, so wondering how it should be done so I don't end up duplicated code that's different in signature only?

Any advice for a better approach in this kind of scenario?

like image 295
user2727195 Avatar asked May 03 '17 20:05

user2727195


People also ask

What are supertypes and subtypes?

A supertype is a generic entity type that has a relationship with one or more subtypes. A subtype is a sub-grouping of the entities in an entity type that is meaningful to the organization and that shares common attributes or relationships distinct from other subgroups. Subtypes inherit all supertype attributes.

Does Golang have types?

It provides several built-in types such as string, bool, int and float64. Go supports composite types such as array, slice, map and channel. Composite types are made up of other types – built-in types and user-defined types.

What is underlying type in Go?

According to Go spec, there is an underlying type of every type: Each type T has an underlying type: If T is one of the predeclared boolean, numeric, or string types, or a type literal, the corresponding underlying type is T itself.

What is the type of a type in Golang?

Type is the base interface for all data types in Go. This means that all other data types (such as int , float , or string ) implement the Type interface. Type is defined in the reflect header.


2 Answers

This is where golang interfaces can shine.

It's worth noting, however, that it's difficult to write subclass/inheritance code in golang. We'd prefer thinking of it as composition.

type EntityVO interface {
    GetName() string
    SetName(string) error
    GetType() string
    ...
}

type EntityVOImpl struct {
    EntityName    string
    EntityType    string
    PublicationId string
    Version       string
}

func (e EntityVOImpl) GetName() string {
    return e.EntityName
}

...

type ArticleVOImpl struct {
    EntityVOImpl
    ContentSize string
    Created     string
}

type CollectionVOImpl struct {
    EntityVO
    ProductId string
    Position string
}

// CODE

func (e *Entity) RequestList(entityVO valueObject.EntityVO) (valueObject.EntityVO, error) { 
    // some code
}

In addition, as long as your interface files are shared, I don't think there should by any problem sending/marshalling/unmarshalling the structs over the wire.

like image 165
Vervious Avatar answered Oct 18 '22 04:10

Vervious


The second parameter of json.Unmarshal is a "universal" interface{} type. I think similar approach is applicable to your case.

  1. Define data type for storing web service properties which may differ for each entity, e.g.

    type ServiceDescriptor struct {
      URI string
      //other field/properties...
    }
    
  2. Function for populating the entity may look like

    func RequestList(desc *ServiceDescriptor, v interface{}) error {
        //Retrieve json data from web service
        //some code
    
        return json.Unmarshal(data, v)
    }
    
  3. You can call the function to populate different type of entities, e.g.

    desc := &ServiceDescriptor{}
    
    article := ArticleVO{}
    desc.URI = "article.uri"
    //...
    //You must pass pointer to entity for 2nd param
    RequestList(desc, &article)
    
    collection := CollectionVO{}
    desc.URI = "collection.uri"
    //...
    //You must pass pointer to entity for 2nd param
    RequestList(desc, &collection)
    
like image 42
putu Avatar answered Oct 18 '22 05:10

putu