Композиция, объединяющая данные и функции с интерфейсами и структурами

Мне интересно, если это что-то, что сделано в Go или я думаю об этом все неправильно: сочинять type x interface а также type x struct поэтому мои методы интерфейса также имеют доступ к определенным данным:

Программист C по моему хочет сделать это:

type PluginHandler interface {
    onLoad()
    pm *PluginManager
}
func (ph PluginHandler) onLoad() {
    pm.DoSomething()
}

Там у меня есть интерфейс, определенный с функцией, но также некоторые данные, которые я хочу передать этим функциям, но это синтаксическая ошибка.

Так это что-то выполнимое в Go через какой-то другой метод, или я просто думаю о проблеме неправильно?

3 ответа

Решение

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

Если у вас есть интерфейс, вам нужен другой тип для реализации методов, указанных в интерфейсе. Например, если другой тип реализует onLoad метод, они автоматически (неявно) реализуют интерфейс PluginHandler,

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

type PluginHandler interface {
    onLoad(*PluginManager)
}

struct SomeType {
    // ...
}

func (s SomeType) onLoad(pm *PluginManager) { // SomeType now implements
    pm.DoSomething()                          // PluginHandler interface.
}

Таким образом, вы можете вводить в зависимости от того, что PluginManager требуется PluginHandler,

Также вы можете использовать SomeType как PluginHandler Тип, где требуется.

func someFuntion(ph PluginHandler) {
    // ...
    ph.onLoad(pm)
    // ...
}

Может вызываться с входным аргументом типа SomeType:

s := SomeType{}
someFunction(s)

TL;DR; Прямого перевода на Go нет.

Длинный ответ:

Go интерфейсы - это всего лишь методы.

Структуры Го являются только данными (с возможностью приемных методов).

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

type Frobnicator interface {
    Frobnicate() error
}

type Widget struct {
    Frobnicator
    WidgetName string
}

Но это не совсем то, о чем ты говоришь.

Я считаю, что лучший ответ на вашу дилемму - сделать шаг назад. Вы сосредотачиваетесь на деревьях, и вам нужно смотреть на лес. Go использует другой подход, чем C или классические ОО-языки, такие как C++ и Java.

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

Просто для записи, вы можете добавить дополнительные методы к существующему типу, введя другой (косвенный) тип как:

type HandlerManager PluginManager

func (x *HandlerManager) onLoad() {
    ((*PluginManager)(x)).DoSomething()
}

И если вам нужно более общее решение, комбинация шаблонов адаптера и стратегии может помочь:

type PluginHandlerAdapter struct{ _onLoad func() }

func (x *PluginHandlerAdapter) onLoad() {
    x._onLoad()
}

Используется как (открытый / закрытый доступ игнорируется):

type PluginManager struct {
    PluginHandlerAdapter
}

func NewPluginManager() *PluginManager {
    res := new(PluginManager)
    res._onLoad = res.DoSomething
    return res
}
Другие вопросы по тегам