Использование разных уровней интерфейсов - PullRequest
0 голосов
/ 13 марта 2020

Я пытаюсь организовать свой код, используя интерфейсы в Go.

У меня есть 2 источника данных: FTP и API. В каждом источнике у меня есть несколько структур, которые изменяют логи c в зависимости от случая.

В этом вопросе я опущу API и придерживаюсь FTP.

Моя проблема связана с невозможность сказать: FTPAcq также является Приобретением

Если FetchMeters(), когда я делаю ftp.Decrypt(nil), я бы хотел, чтобы ftp был "совместим" с FTPAcq

Вот мой код:

package main

import (
    "github.com/dutchcoders/goftp"
    log "github.com/sirupsen/logrus"
    "os"
)

type Acquisition interface {
    FetchMeters() ([]Meter, error)
    Name() string
}

type FTPAcq interface {
    Unzip(file string) string
    Decrypt(file string) string
}

//type APIAcq interface {
//  FetchMeter(meterID string) (Meter, error)
//}

func main() {
    var acqs []Acquisition
    ftp, err := NewFTPDriver(os.Getenv("FTP_USER"), os.Getenv("FTP_PASSWD"), os.Getenv("FTP_ADDR"), os.Getenv("FTP_PORT"))
    if err != nil {
        panic(err)
    }
    ftp1 := NewFTPDriverSGE(*ftp)
    ftp2 := NewFTPDriverTA(*ftp)
    acqs = append(acqs, ftp1, ftp2)
    for _, acq := range acqs {
        tmpMeters, err := acq.FetchMeters()
        if err != nil {
            log.Warn(acq.Name(), " got error :", err)
        }
        log.Info(tmpMeters)
    }
}

type Meter struct {
    ID          string
    OperationID string
    Unit        string
}

//FtpSGE is a implementation of acquisition Interface (see driver.go)
type FTP struct {
    Username string
    Password string
    Url      string
    Port     string
    client   *goftp.FTP
}
type FTPSGE struct {
    FTP
}
type FTPTA struct {
    FTP
}

func (f FTPSGE) Unzip(path string) []string {
    return nil
}
func (f FTPTA) Unzip(path string) []string {
    return nil
}

func (f FTPSGE) Decrypt(path string) []string {
    return nil
}

func (f FTPTA) Decrypt(path string) []string {
    return nil
}

func (ftp FTP) FetchMeters() ([]Meter, error) {
    log.Info(ftp.Name(), " is running")
    files := ftp.Download(nil)
    files = ftp.Decrypt("") // I have several implementation of Decrypt
    files = ftp.Unzip("")   // I have several implementation of Unzip
    log.Info(files)
    return nil, nil
}

func (ftp FTP) Name() string {
    panic("FTP ")
}

func (ftp FTP) Download(files []string) []string {
    panic("implement me")
}

func NewFTPDriver(user, password, url, port string) (*FTP, error) {
    var err error
    ftp := &FTP{
        Username: user,
        Password: password,
        Url:      url,
        Port:     port,
    }
    if ftp.client, err = goftp.Connect(url + ":" + port); err != nil {
        return nil, err
    }
    if err = ftp.client.Login(user, password); err != nil {
        return nil, err
    }
    return ftp, nil
}
func NewFTPDriverSGE(f FTP) *FTPSGE {
    return &FTPSGE{f}
}

func NewFTPDriverTA(f FTP) *FTPTA {
    return &FTPTA{f}
}

В моем случае я получаю:

ftp.Decrypt undefined (type FTP has no field or method Decrypt)

Как мне поступить?

1 Ответ

2 голосов
/ 13 марта 2020

FTP делает не орудие FTPAcq. Он реализует только Acquisition. Он даже не имеет Decrypt() в качестве метода, интерфейса или нет.

FTPSGE и FTPTA реализуют FTPAcq, но они не того же типа, что и FTP.

Я не знаю, что вы ' пытается выполнить sh, но, возможно, стоит попробовать встраивание FTP в FTPSGE и FTPTA. Это дает этим двум типам поля и методы встроенного типа и все же позволяет вам определять дополнительные методы для этих типов (методы для FTPAcq в вашем случае).

Например

type FTPSGE {
    FTP
}
// OR
type FTPSGE {
    *FTP
}

Который вы потом создаете так: x := FTPSGE{ftp1}. Имейте в виду, что это создаст копию из ftp1 внутри x. Если ftp1 имеет тип FTP (не указатель), вся структура копируется. Если ftp1 имеет тип *FTP (указатель, который, похоже, используется), указатель копируется, и x.FTP по-прежнему указывает на те же данные, что и ftp1.

. означает, что FTPSGE будет реализовывать как Acquisition, так и FTPAcq.

. Вам нужно быть осторожным в том, реализованы ли интерфейсы для значения или указателя: func (a A) Something() против func (a *A) Somthing().

Вот некоторые сведения о методах, интерфейсах и встраивании.

  1. https://www.ardanlabs.com/blog/2014/05/methods-interfaces-and-embedded-types.html
  2. https://travix.io/type-embedding-in-go-ba40dd4264df
  3. https://golang.org/doc/effective_go.html (и много другой информации)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...