Создайте функцию, для которой требуется другая логика повторения в качестве предварительного условия (чистый код) - PullRequest
0 голосов
/ 30 сентября 2018

У меня есть следующий файл yaml, который мне нужен для parse (синтаксический анализ работает должным образом), и мне нужно предоставить data из содержимого файла yaml, которое должно быть открыто следующими отделенными функциями

Мне нужно предоставить следующие функции (вот пример некоторых из этих функций, нужно больше с тем же шаблоном ...)

getApps ()

getServices ()

GetApp (имя приложения)

GetServiceForApp (имя приложения)

Это код (который работает ...)

var DMZ = []byte(`
applications:
  - name: app1
    type: php
    src: /app1
    host: us
    use: 
      - redis
      - mysql

  - name: app2
    type: rust
    src: /app2
    host: eu
    use: 
      - mongo
      - mysql

  - name: app3
    type: golang
    src: /app3
    host: us
    use: 
      - postgress
      - mysql


services:
  - name: mongo
    type: db
    host: us

  - name: mysql
    type: db
    host: eu

  - name: postgress
    type: db
    host: us

  - name: redis
    type: db
    host: us   
`)

Это структуры

type DMZ struct {
  Applications       []*Applications   `yaml:"applications,omitempty"`
  Services           []*Services       `yaml:"services,omitempty"`
}

type Applications struct {
  Name        string
  Type        string
  Src        string            `yaml:"src,omitempty"`
  use        []Use             `yaml:"use,omitempty"`
}
type Services struct {
  Name        string
  Type        string
  Host        string            `yaml:"host,omitempty"`
}
type Use struct {
  Name       string     `yaml:"name,omitempty"`
  host       string     `yaml:"host,omitempty"`
  Type       string     `yaml:"type,omitempty"`
}



// Parse file
func Parse(yamlContent []byte) (out DMZ, err error) {
  dmz := DMZ{}
  err = yaml.Unmarshal([]byte(yamlContent), &dmz)
  if err != nil {
    logs.Error("Yaml file is not valid, Error: " + err.Error())
  }
  return dmz, err
}

Поскольку функция Parse является для каждого для всех необходимых функций (который я перечислил выше) Интересно, как лучше создать их, создать простую функцию, которая каждый раз вызывает функцию parse, а затем выполняет логику (не проблема) но мне интересно, есть ли лучший подход , который следует принципам чистого кода для Golaнг, с ' интерфейс / инъекции зависимости' ?

ОБНОВЛЕНИЕ:

Я хочу избегать таких действий, как следование, предположим, что мне нужно вызывать эти функции из различных пакетов или даже другой репозиторий GitHub как лучше это делать с чистым кодом Golang .

func getApps(){

 dmz := Parse()
....
}


func getServices(){

 dmz := Parse()
....

}


func getApp(appname string){

 dmz := Parse()
....

}


func GetServiceForApp(appname string){

 dmz := Parse()
....

}

И мне нужно больше функций с тем же шаблоном...

Что мне нужно для решения Clean Code , использующего интерфейс / внедрение зависимостей , как лучший пример кода в Golang

Если что-то не такясно, пожалуйста, дайте мне знать:)

Ответы [ 3 ]

0 голосов
/ 03 октября 2018

Вы можете определить интерфейс и предоставить реализации в структуре

type DMZI interface {
    GetApps() []Application
    GetService() []Service
    GetApp(name string) (Application, error)
    GetServiceForApp(name string) ([]string, error)
}

type DMZ struct {
    Application []Application `yaml:"applications,omitempty"`
    Service     []Service     `yaml:"services,omitempty"`
}

func (dmz DMZ) GetApps() []Application {
    return dmz.Application
}

func (dmz DMZ) GetService() []Service {
    return dmz.Service
}

func (dmz DMZ) GetApp(name string) (Application, error) {
    for _, app := range dmz.Application {
        if app.Name == name {
            return app, nil
        }
    }
    return Application{}, fmt.Errorf("Did not find application with name %s", name)
}

func (dmz DMZ) GetServiceForApp(name string) ([]string, error) {
    app, err := dmz.GetApp(name)
    if err != nil {
        return []string{}, err
    }
    return app.Use, nil
}

type Application struct {
    Name string
    Type string
    Src  string   `yaml:"src,omitempty"`
    Use  []string `yaml:"use,omitempty"`
}
type Service struct {
    Name string
    Type string
    Host string `yaml:"host,omitempty"`
}

// Parse file
func Parse(yamlContent []byte) (out DMZI, err error) {
    dmz := DMZ{}
    err = yaml.Unmarshal([]byte(yamlContent), &dmz)
    if err != nil {
        fmt.Println("Yaml file is not valid, Error: " + err.Error())
    }
    return dmz, err
}

Таким образом, вы можете вызывать методы в возвращенном интерфейсе, например,

fmt.Printf("Apps : %+v\n", dmz.GetApps())
fmt.Printf("Service : %+v\n", dmz.GetService())

UPDATE

основной метод в соответствии с запросом в комментарии

func main() {
    dmz, err := Parse([]byte(ymlStr))
    if err != nil {
        panic(err)
    }
    fmt.Printf("Apps : %+v\n", dmz.GetApps())
    fmt.Printf("Service : %+v\n", dmz.GetService())
}

Будет печатать

Apps : [{Name:app1 Type:php Src:/app1 Use:[redis mysql]} {Name:app2 Type:rust Src:/app2 Use:[mongo mysql]} {Name:app3 Type:golang Src:/app3 Use:[postgress mysql]}]
Service : [{Name:mongo Type:db Host:us} {Name:mysql Type:db Host:eu} {Name:postgress Type:db Host:us} {Name:redis Type:db Host:us}]
0 голосов
/ 03 октября 2018

Анализ значения внутри структуры типа указателя, которая будет хранить значение внутри структуры, на которую указывает указатель.Затем Create метод получает все методы, из которых вы хотите получить значение приложения или службы внутри структуры.

Используя приемник указателя во всех методах, вы сможете получить доступ к исходной структуре, которая обновляется, когдапарсинг yaml.

Создайте указатель на пустой экземпляр структуры и передайте его как приемник метода.Затем получите доступ к этой структуре в unmarshal, чтобы обновить данные yaml в исходной структуре.Получите доступ к обновленной структуре в каждой функции, обратившись к значению исходной структуры, используя приемник указателя на метод.

package main

import (
    "fmt"
    "log"

    yaml "gopkg.in/yaml.v2"
)

var dmz = []byte(`
applications:
  - name: app1
    type: php
    src: /app1
    host: us
    use: 
      - redis
      - mysql

  - name: app2
    type: rust
    src: /app2
    host: eu
    use: 
      - mongo
      - mysql

  - name: app3
    type: golang
    src: /app3
    host: us
    use: 
      - postgress
      - mysql


services:
  - name: mongo
    type: db
    host: us

  - name: mysql
    type: db
    host: eu

  - name: postgress
    type: db
    host: us

  - name: redis
    type: db
    host: us   
`)

type DMZ struct {
    Applications []*Applications `yaml:"applications,omitempty"`
    Services     []*Services     `yaml:"services,omitempty"`
}

type Applications struct {
    Name string
    Type string
    Src  string `yaml:"src,omitempty"`
    use  []Use  `yaml:"use,omitempty"`
}
type Services struct {
    Name string
    Type string
    Host string `yaml:"host,omitempty"`
}
type Use struct {
    Name string `yaml:"name,omitempty"`
    host string `yaml:"host,omitempty"`
    Type string `yaml:"type,omitempty"`
}

func main() {
    dm := &DMZ{}
    result, err := dm.Parse(dmz)
    dm.getApp("app1")
    if err != nil {
        fmt.Println(err)
    }
    fmt.Println(result)
    fmt.Println(dm.getApp("app2"))
    fmt.Println(dm.GetServiceForApp("mongo"))
}

func (dmz *DMZ) getApps() []*Applications {
    return dmz.Applications
}

func (dmz *DMZ) getServices() []*Services {
    return dmz.Services
}

func (dmz *DMZ) getApp(appname string) *Applications {
    for _, value := range dmz.Applications {
        if appname == value.Name {
            fmt.Println((*value).Name)
            return value
        }
    }
    return nil
}

func (dmz *DMZ) GetServiceForApp(appname string) *Services {
    for _, value := range dmz.Services {
        if appname == value.Name {
            return value
        }
    }
    return nil
}

// Parse file
func (dmz *DMZ) Parse(yamlContent []byte) (out *DMZ, err error) {
    err = yaml.Unmarshal([]byte(yamlContent), &dmz)
    if err != nil {
        log.Fatal("Yaml file is not valid, Error: " + err.Error())
    }
    return dmz, err
}

Рабочий код на Детская площадка

Если вы хотите свой кодчтобы быть более чистым, вы также можете пропустить структуру, возвращаемую из функции разбора.Поскольку мы передаем получатель типа указателя и обновляем исходную структуру следующим образом:

package main

import (
    "fmt"
    "log"

    yaml "gopkg.in/yaml.v2"
)

var dmz = []byte(`
applications:
  - name: app1
    type: php
    src: /app1
    host: us
    use: 
      - redis
      - mysql

  - name: app2
    type: rust
    src: /app2
    host: eu
    use: 
      - mongo
      - mysql

  - name: app3
    type: golang
    src: /app3
    host: us
    use: 
      - postgress
      - mysql


services:
  - name: mongo
    type: db
    host: us

  - name: mysql
    type: db
    host: eu

  - name: postgress
    type: db
    host: us

  - name: redis
    type: db
    host: us   
`)

type DMZ struct {
    Applications []*Applications `yaml:"applications,omitempty"`
    Services     []*Services     `yaml:"services,omitempty"`
}

type Applications struct {
    Name string
    Type string
    Src  string `yaml:"src,omitempty"`
    use  []Use  `yaml:"use,omitempty"`
}
type Services struct {
    Name string
    Type string
    Host string `yaml:"host,omitempty"`
}
type Use struct {
    Name string `yaml:"name,omitempty"`
    host string `yaml:"host,omitempty"`
    Type string `yaml:"type,omitempty"`
}

func main() {
    dm := &DMZ{}
    dm.Parse(dmz)
    fmt.Println(dm.getApp("app2"))
    fmt.Println(dm.GetServiceForApp("mongo"))
}

func (dmz *DMZ) getApps() []*Applications {
    return dmz.Applications
}

func (dmz *DMZ) getServices() []*Services {
    return dmz.Services
}

func (dmz *DMZ) getApp(appname string) *Applications {
    for _, value := range dmz.Applications {
        if appname == value.Name {
            fmt.Println((*value).Name)
            return value
        }
    }
    return nil
}

func (dmz *DMZ) GetServiceForApp(appname string) *Services {
    for _, value := range dmz.Services {
        if appname == value.Name {
            return value
        }
    }
    return nil
}

// Parse file
func (dmz *DMZ) Parse(yamlContent []byte) {
    if err := yaml.Unmarshal([]byte(yamlContent), &dmz); err != nil {
        log.Fatal("Yaml file is not valid, Error: " + err.Error())
    }
}

Поскольку мы можем заметить, что функция Parse станет более чистой, поскольку мы ничего не возвращаем из нее, мы просто обновляем исходную структуруиспользование приемника методов, который является гораздо лучшим способом достижения того, чего вы пытались достичь.

Вы также можете выбрать реализацию интерфейса, определив методы в struct как приемник, для которого вы пытаетесь реализовать интерфейс.as:

package main

import (
    "fmt"
    "log"

    yaml "gopkg.in/yaml.v2"
)

type DI interface {
    GetApps() []*Applications
    GetServices() *Services
}

var dmz = []byte(`
applications:
  - name: app1
    type: php
    src: /app1
    host: us
    use: 
      - redis
      - mysql

  - name: app2
    type: rust
    src: /app2
    host: eu
    use: 
      - mongo
      - mysql

  - name: app3
    type: golang
    src: /app3
    host: us
    use: 
      - postgress
      - mysql


services:
  - name: mongo
    type: db
    host: us

  - name: mysql
    type: db
    host: eu

  - name: postgress
    type: db
    host: us

  - name: redis
    type: db
    host: us   
`)

type DMZ struct {
    Applications []*Applications `yaml:"applications,omitempty"`
    Services     []*Services     `yaml:"services,omitempty"`
}

type Applications struct {
    Name string
    Type string
    Src  string `yaml:"src,omitempty"`
    use  []Use  `yaml:"use,omitempty"`
}
type Services struct {
    Name string
    Type string
    Host string `yaml:"host,omitempty"`
}
type Use struct {
    Name string `yaml:"name,omitempty"`
    host string `yaml:"host,omitempty"`
    Type string `yaml:"type,omitempty"`
}

func main() {
    dm := &DMZ{}
    dm.Parse(dmz)
    fmt.Println(dm.getApp("app2"))
    fmt.Println(dm.GetServiceForApp("mongo"))
}

func (dmz *DMZ) GetApps() []*Applications {
    return dmz.Applications
}

func (dmz *DMZ) GetServices() []*Services {
    return dmz.Services
}

func (dmz *DMZ) getApp(appname string) *Applications {
    for _, value := range dmz.Applications {
        if appname == value.Name {
            fmt.Println((*value).Name)
            return value
        }
    }
    return nil
}

func (dmz *DMZ) GetServiceForApp(appname string) *Services {
    for _, value := range dmz.Services {
        if appname == value.Name {
            return value
        }
    }
    return nil
}

// Parse file
func (dmz *DMZ) Parse(yamlContent []byte) {
    if err := yaml.Unmarshal([]byte(yamlContent), &dmz); err != nil {
        log.Fatal("Yaml file is not valid, Error: " + err.Error())
    }
}

Примечание:

Обобщения удобны, но они сложны в системе типов и во время выполнения.Мы еще не нашли дизайн, который дает ценность, пропорциональную сложности, хотя мы продолжаем думать об этом.Между тем, встроенные в Go карты и фрагменты, а также возможность использовать пустой интерфейс для создания контейнеров (с явным распаковыванием) означают, что во многих случаях можно написать код, который делает то, что позволят дженерики, если не так гладко.

0 голосов
/ 30 сентября 2018

Я немного изменил ваш код и сделал то, о чем я думаю вы просите, то есть всегда вызывать "Parse" всякий раз, когда вы создаете новый экземпляр DMZ.Вот как вы могли бы сделать это, используя Dargo .Посмотрите внизу, чтобы увидеть, как код связывает DMZ в ServiceLocator и как получить новые экземпляры DMZ

type DMZ struct {
    Applications []*Applications `yaml:"applications,omitempty"`
    Services     []*Services     `yaml:"services,omitempty"`
}

// This method is called every time DMZ is created via the Dargo API
func (dmz *DMZ) DargoInitialize(ioc.Descriptor) error {
    // get ur bytes from... wherever
    Parse(dmz, []byte{})
}

type Applications struct {
    Name string
    Type string
    Src  string `yaml:"src,omitempty"`
    use  []Use  `yaml:"use,omitempty"`
}
type Services struct {
    Name string
    Type string
    Host string `yaml:"host,omitempty"`
}
type Use struct {
    Name string `yaml:"name,omitempty"`
    host string `yaml:"host,omitempty"`
    Type string `yaml:"type,omitempty"`
}

// Parse file
func Parse(dmz *DMZ, yamlContent []byte) (out *DMZ, err error) {
    err = yaml.Unmarshal([]byte(yamlContent), &dmz)
    if err != nil {
        logs.Error("Yaml file is not valid, Error: " + err.Error())
    }
    return dmz, err
}

func useDargo() error {
    locator, err := ioc.CreateAndBind("example", func(binder ioc.Binder) error {
        binder.Bind("DMZ", &DMZ{}).InScope(ioc.PerLookup)
    })
    if err != nil {
        return err
    }

    // This is how you would get your instances of DMZ
    locator.GetDService("DMZ")
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...