Как правильно структурировать пакет с подпакетами в Go, где один тип будет получателем для большинства методов? - PullRequest
1 голос
/ 23 февраля 2012

Я только начинаю изучать Go, поэтому, если я пропустил что-то очевидное, Go easy: -)

В любом случае, я сейчас на стадии разработки, написание библиотеки утилит, которая сделаетнемного проще взаимодействовать с x-go-binding .(Я делал это раньше с Python и xpyb.) Например, это поможет с запросом информации, определенной в EWMH spec и привязкой ключей к функциям обратного вызова.(И многое другое.) В качестве моей первоначальной идеи для макета пакета рассмотрим:

  • xutil
    • ewmh
    • keybind

Где у каждого свой пакет.(Подобно тому, как настраивается пакет изображений стандартной библиотеки.)

В моей ситуации уникально то, что почти каждый вызов x-go-binding требует некоторой комбинации объекта соединения xgb или идентификатора корневого окна.Поэтому, для меня имеет смысл хранить эту информацию в такой структуре:

type XUtilConnection struct {
    conn xgb.Conn
    root xgb.Id
    // a few other things, like a mapping of events to callbacks
}

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

xconn = xutil.NewXUtilConnection(blah blah)

И это можно использовать как:

xconn.get_active_window()
xconn.bind_key("Shift-a", my_callback_fun)

Также могут быть такие функции, как:

keybind.get_keycode("a")
ewmh.get_atom("_NET_ACTIVE_WINDOW")

Моя проблема, конечно, в том, что приемники, насколько мне известно, могут быть только таких типов, которыебыли объявлены в той же упаковке.Если я отделю свои пакеты, я не смогу использовать свой тип XUtilConnection в качестве получателя ни в одном из моих подпакетов.

Я подозреваю, что мой ответ будет состоять в том, что этот один большой пакет будет разделен на разные логические файлы, ноЯ боюсь, что это может привести к беспорядку пространства имен.(Например, реализация спецификации EWMH, вероятно, порядка 100+ функций.)

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

Буду очень признателен за любой совет в любом месте моего процесса проектирования.Спасибо!

Ответы [ 2 ]

2 голосов
/ 23 февраля 2012

Я бы предложил использовать embedding .

In package xutil:

  type XUtilConnection struct {
      *ewmh.EWMH        // Embed all methods of *ewmh.EWMH
      *keybind.KeyBind  // Embed all methods of *keybind.KeyBind
  }

In package xutil/ewmh:

  type EWMH struct {
      Conn xgb.Conn
      Root xgb.Id
      // and any additional fields that are needed
  }

  // Some EWMH methods:
  func (e *EWMH) GetAtom(name string) { ... }
  func (e *EWMH) ...

In package xutil/keybind:

  type KeyBind struct {
      Conn xgb.Conn
      Root xgb.Id
      // and any additional fields that are needed
  }

  // Some keybind methods:
  func (k *KeyBind) GetKeyCode(s string) { ... }
  func (k *KeyBind) ...

Это позволит вам напрямую вызывать методы EWMH и KeyBind для значений типа *XUtilConnection:

var c *XUtilConnection = ...
c.GetAtom("_NET_ACTIVE_WINDOW")  // Call (*emwh.EWMH).GetAtom(string)
c.GetKeyCode("a")                // Call (*keybind.KeyBind).GetKeyCode(string)
0 голосов
/ 24 февраля 2012

Я не уверен, правильно ли я понял проблему (я сбит с толку, когда вижу имена пакетов, где они, кажется, обсуждаются как получатели методов?), Но я предполагаю, что передача интерфейса вместо структуры [*] будет включить удовлетворение его из любой упаковки. Также всегда можно сделать что-то вроде (полностью непроверенный код):

package foo

type Foo interface { Bar(); Baz() }

----
package qux

import "foo"

type qux struct { foo.Foo; myStuff t }

func Foo(f foo.Foo) foo.Foo {
    return qux{f, &t{}}
}

func (q qux) Bar() {
    // smthg
}

Например. «переопределить» f.Bar в пакете qux и «наследовать» f.Baz() без изменений.

...