Как-то у нас с
belnetmon возник спор про абстрагирование частей программы друг от друга.
Я, когда мне не влом, делаю классическим способом - выделяю зависимости в интерфейсы или абстрактные базовые классы, потом от них наследую реализации и в итоге собираю из этого конечный результат. Но из этого получается в пару раз больше кода и модулей, чем если бы просто реализовать нужную функциональность, не заморачиваясь на абстрагирование.
Вот сейчас опять наткнулся на эту шизу. Был класс, генерящий кросс-таблицы(они же шахматки, они же двумерный вариант кубов). Заполнялся из датасета, вызовом метода Fill(DS:TDataset). Один юнит, в котором класс TCrossTable с этим методом.
В бухгалтерии постоянно возникает задача - кроме основной шахматки, нужны промежуточные итоги, общие итоги, часто с нетривиальным критериями группировки.
Обходил я это, добавляя в запрос, который заполняет датасет, всякие хитрые union и join, которые повторно вызывали основной запрос(в виде selectable stored procedure), группируя его заново. В итоге получалась заданная хитрая шахматка. Но: 1)запрос усложнялся 2)для каждого итога приходилось повторно выполнять запрос 3)полученный датасет начинал выглядеть как набор безумного бреда из цифр, хотя его было бы неплохо тоже просматривать в линейном табличном виде, для поиска заданных сумм.
Решил я передвинуть расчет промежуточных сверток итогов на клиента. Давно пора. Для этого надо впихнуть между датасетом и кросс-таблицей еще один слой, который на каждую запись датасета будет по хитрым условиям генерить несколько записей, попадающих в основную шахматку и итоги.
И вот задача - в каком виде сделать этот слой. Можно взять заполняемый вручную TClientDataset. А можно абстрагировать TCrossTable от датасета.
Выбрал второе решение. Итого один юнит и один класс превратились в:
1) Два базовых абстрактных класса для полей и источника данных.
2) TCrossTable получающий в Fill абстрактный источник данных
3) Два наследника для полей и источника данных, реализующих их поверх TDataset.
+2 юнита,+4 класса - цена абстрагирования. И это я всего лишь повторил уже существующую функциональность. А сейчас еще буду делать реализацию для расчета итогов.
И, скорее всего, придется сделать еще один класс-обертку, который будет на вход получать датасет, внутри себя держать класс кросс-таблицы, а абстрактный источник данных для него загружать из настроек отчета, для того чтобы настройками описывать этот самый промежуточный слой между датасетом и кросс-таблицей.
Теперь я наконец понял, почему крупные проекты содержат огромное количество мелких файлов.