2015-04-16 2 views
2

У меня есть структура, которую реализуют два других объекта. В этом случае typeA и B repo's. Здесь есть код инициализации, который представлен здесь как эллипсы. Код инициализации полностью дублируется между обоими конструкторами и не имеет большого значения, в то время как у меня есть только два dbRepo, но по мере того, как я создаю больше, я буду немного беспокоиться о плохой практике. Есть ли способ обобщить это с помощью интерфейса?Общая структура построения структуры Golang

type dbRepo struct { 
    foo string 
    bar string 
} 

type typeARepo dbRepo 
type typeBRepo dbRepo 

func newTypeARepo(foo, bar string) { 
    ... 
} 

func newTypeBRepo(foo, bar string) { 
    ... 
} 
+1

Ваш пример кода не выглядит как что-то можно было бы сделать в дороге. Но, чтобы быть уверенным, не могли бы вы немного разобраться в своем случае? Например, почему два подтипа dbRepo? – wldsvc

+0

Как и где принято решение о создании типа A или B? – wldsvc

+0

Есть два подтипа, потому что каждый из них имеет разные функции, которые будут называться на них, в зависимости от типа репо, которым они являются. Например, вызов в пользовательскую базу данных вместо базы данных элементов. У меня будут разные запросы и функции, которые я хочу сделать на основе репозитория. Создание и назначение выполняются в основной функции в другом месте. Все это свободно следит за чистой архитектурой в Go. – user2402831

ответ

3

Практика Я лично наблюдал в Go (и это также то, что рекомендуется в эффективном Go или начать работу с учебниками Go) - это просто определить функцию NewdbRepo и использовать ее для всех мнений. Реализация будет выглядеть примерно так:

func NewdbRepo(f, b string) *dbRepo { 
    return &dbRepo{ foo:f, bar:b} 
} 

Вы не можете на самом деле определить конструктор, как вы в большинстве C, как языки, так что вы только должны обеспечить пакетное область видимости способ сделать конструкцию для вас. Кроме того, если вы не используете составные литералы (стиль инициализации, который я использую в своей реализации NewdbRepo), то вы можете найти это достаточно кратким для своих нужд.

+0

Я признаю, что у вас нет конструкторов в традиционном смысле слова, но функция, которая строит, а затем возвращает структуру, кажется мне симпатичной конструкторной функцией! Я отвлекся! Я смог сделать это, а затем использовать утверждение типа в 'NewTypeARepo()' func для достижения желаемого результата. – user2402831

+0

Подобная фабричная функция не является конструктором. Это заводская функция (как и на других языках). Конструктор требует, чтобы вы его вызывали, тем самым защищая вас от выделения неинициированной (ошибочной) структуры нулевого значения. Более того, часть «dbRepo» буквального «NewdbRepo» явно не связана с типом «dbRepo». Если бы вы использовали некоторые инструменты автоматического рефакторинга для переименования «dbRepo» в «databaseRepo», у них не было бы никакого способа узнать, что «NewdbRepo» также нужно реорганизовать. Это может быть очень проблематичным при реорганизации большого проекта. – eshalev

+0

@eshalev, если вы прочтете ответ, он достаточно четко объясняет все это. В Go нет конструкторов, как указано: «Вы не можете определить конструктор так же, как и на большинстве C-подобных языков, поэтому вы просто должны предоставить пакетный метод для построения для вас», а также, как указано, этот шаблон - это то, что представленный в документации относительно языка. И нет, конструктор не «требует, чтобы вы его называли», что является правилом языка и не имеет ничего общего с «конструкторами», которые являются гораздо более четко определенным понятием и ведут себя иначе, чем от одного языка к другому. – evanmcdonnal

2

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

func newDbRepo(foo, bar string) dbRepo { 
     // ... 
} 

Затем вы можете использовать его с преобразованием типа:

a := typeARepo(newDbRepo("foo", "bar")) 
b := typeBRepo(newDbRepo("foo", "bar")) 
1

Определить неэкспортируемыми FUNC от типа, что делает инициализацию, то вы можете создать несколько конструкторов, которые называют его, например:

func (db *dbRepo) init(){ 
    if len(db.foo) > 0 { 
     //do foo init 
    } 
    if len(db.bar) > 0 { 
     // do bar init 
    } 
    // do generic init 
} 

func NewRepo(foo, bar string) *dbRepo { 
    repo := &dbRepo{foo: foo, bar: bar} 
    repo.init() 
    return repo 
} 

func NewFooRepo(foo string) *dbRepo { 
    repo := &dbRepo{foo: foo} 
    repo.init() 
    return repo 
} 
Смежные вопросы