Я все еще изучаю способ ведения дел в Go, исходя из фона C ++. Я ищу обратную связь, сравнивающую наследование ООП с составом интерфейса.
У меня есть ситуация проектирования в программе Go, где, если бы я реализовывал на C ++, я бы решил с помощью абстрактного базового класса.
Предположим, мне нужен базовый класс, который имеет много разработчиков. Базовый класс имеет общие методы, которые работают с абстрактными элементами данных. Разные реализации Worker предоставляют операции CRUD для разных типов элементов, но все рабочие используют общие методы базового класса для общей работы.
В C ++ я мог бы сделать это так
class IItem
{
// virtual methods
};
class IWorker
{
public:
// one of many virtual functions that deal with IItem CRUD
virtual IItem* createItem() = 0;
// concrete method that works on interfaces
void doWork()
{
IItem* item = createItem();
// do stuff with an IItem*
}
};
class Toy : public IItem
{
};
// one of many kinds of workers
class ElfWorker : public IWorker
{
public:
ElfWorker()
{
// constructor implicitly calls IWorker()
}
IItem* createItem() override
{
return new Toy;
}
};
В Go у вас нет абстрактных виртуальных методов, таких как IWorker :: createItem (). Конкретные классы должны снабжать базу интерфейсом или функцией, которая делает правильные вещи.
Так что я думаю, что это тот случай, когда код Go интерфейса ew.ItemCRUD должен быть явно установлен с указателем на ElfWorker.
Эльф знает, как создатьItem (), который в его случае оказывается игрушечным объектом. Другие работники будут реализовывать свой собственный ItemCRUD для своих объектов данных.
type Item interface {
// various methods
}
type ItemCRUD interface {
create() Item
// other CRUD
}
type Worker struct {
ItemCRUD // embedded interface
}
func (w *Worker) doWork() {
item := w.create()
// do stuff with item
}
type Toy struct {
}
type ElfWorker struct {
Worker // embedded
// ..
}
func NewElfWorker() *ElfWorker {
ew := &ElfWorker{}
ew.ItemCRUD = ew // <-- #### set Worker ItemCRUD explicitly ####
return ew
}
func (ew *ElfWorker) createItem() Item {
return &Toy{}
}
// more ElfWorker Item CRUD
func bigFunction(w *Worker) {
// ...
w.doWork()
// ..
}
Так что часть, с которой я немного борюсь, это явная настройка. Похоже, что "Go way" композиции требует этого явного шага, если я хочу, чтобы базовый класс Worker предоставлял общие методы для Items.
Мысли?