Хорошо ли реализовать миксин шаблон с помощью макроса #include в C ++ - PullRequest
0 голосов
/ 28 июня 2018

Как мы знаем, mixin - это шаблон проектирования, который "вставляет" некоторые поведения в другой класс. Например, в Ruby мы можем написать код, подобный этому

module Flyable
  def fly
    puts "I'm flying";
  end
end

class Bird
  include Flyable
end

C ++ не имеет поддержки смешивания на уровне языка, но мы можем использовать множественное наследование для вставки кода в производный класс. Но у этого решения все еще есть свои проблемы, такие как наследование алмазов, , неспособность переопределить виртуальный метод в интерфейсе, неспособность получить доступ к элементам из "родственных" модулей и т. Д.

Позже я обнаружил, что могу использовать макрос #include для вставки сегмента кода в определение класса для достижения смешивания:

// in Flyable.h
public:
void fly() {
    // do something ...
}
float flySpeed;

И в другом файле

// in Bird.h
class Bird {
#include "Flyable.h"
};

Таким образом, все переменные-члены и функции вставляются в класс Bird.

У этого решения нет очевидного недостатка. Коды хорошо организованы в разные файлы. Возможных конфликтов имен можно избежать с помощью тщательно разработанных модулей без наложения функций / правил.

Но все же я боюсь, что есть некоторые проблемы, которые я еще не видел. Есть ли проблемы с этим типом миксина?


Редактировать

Я знаю, что использование #include внутри определения класса странно. Но это решит проблему. И программисты могут привыкнуть к этому, если он действительно используется в проекте. Итак, я хочу знать, есть ли практическая причина, по которой мы должны избегать такого кода? Не только это уродливо или странно, либо никто так не пишет.


Редактировать

Я забыл объяснить назначение кода. Вкратце, это решение проблемы алмазов без виртуального наследования. Насколько я понимаю, коренной причиной проблемы с бриллиантами является злоупотребление ООП. "Птица" - это "FlyableAnimal, FlyableAnimal" - это "Животное, Птица" - это "Плотоядное животное, Плотоядное животное" - это "Животное. Реальное намерение такого рода злоупотреблений - повторное использование кода, поэтому вместо отношений «есть» можно «лучше». И миксин может принести «-белые» отношения.

В C ++, mixin может быть достигнуто множественным наследованием. Это довольно хорошо, но это отключит полиморфизм. Например, у нас есть интерфейс Animal с чисто виртуальными функциями, и мы хотим, чтобы Bird реализовал их. Тогда мы не можем использовать множественное наследование для внедрения реализации в класс Bird. Есть несколько других методов для достижения этой цели, например, композиция. Но я не видел такого простого решения, как настоящий миксин. Вот почему я подумал о #include для mixin.

1 Ответ

0 голосов
/ 28 июня 2018

У этого решения нет очевидного недостатка.

Недостатки:

  • разработчикам, которые позже присоединятся к вашему проекту, придется многому научиться, прежде чем стать эффективными разработчиками в проекте. Это очевидно только после того, как вам пришлось некоторое время поддерживать нестандартные хаки других людей в других проектах.

  • неожиданно; это приведет к ошибкам, вызовет много задержек в разработке («эй, я написал это, но он не компилируется». / «Да, в этом файле есть странная вещь включения, и вам нужно написать код, подобный этому вместо ").

Коды хорошо организованы в разные файлы.

Вся отрасль применяет следующие соглашения для организации кода:

  • все внутри домена, в пределах одного API (будь то один класс или единый набор свободных функций) и обычно в пределах не более двух файлов: один для объявлений, один для определений.

  • там, где это возможно, хранить только заголовки

  • там, где это невозможно, напишите реализацию в классе .impl или _impl и включите ее в заголовок (это не является стандартом де-факто, но вы видите, что оно используется с шаблонным кодом).

Ваше решение явно отличается от этого (то есть явно не организовано в разные файлы ).

Возможных конфликтов имен можно избежать с помощью тщательно разработанных модулей без наложения функций / правил.

Когда люди делают это различие («да, код можно обслуживать, вам просто нужно приложить дополнительные усилия»), они думают, что вы смотрите на проблему, применяете решение, фиксируете, и проблема решается.

Части, которые вы склонны забывать при этом:

  • вам придется принимать одно и то же решение снова и снова, на протяжении всего жизненного цикла вашего проекта.
  • вам придется заставлять своих коллег принимать одно и то же решение снова и снова на протяжении всего жизненного цикла вашего проекта (в том числе, когда вы сами больше не участвуете в нем). Это сложно, со стандартным решением, не говоря уже о нестандартных.

Но все же я боюсь, что есть некоторые проблемы, которые я еще не видел. Есть ли проблемы с этим типом миксина?

Подведем итог (tldr):

  • у вас будет увеличиваться постоянное техническое обслуживание на протяжении всего проекта.

  • это нелогично для любых новых сотрудников и увеличивает стоимость других, присоединяющихся к вашему проекту.

  • все разработчики, которые следуют своей интуиции / полученному опыту, ожидают увидеть что-то еще в вашем проекте (увеличение WTF / sloc в вашем коде).

  • это вызовет трения в вашей команде в будущем; по крайней мере, если в вашей команде есть разработчики, которые заботятся о качестве и простоте использования вашего кода.

...