Оператор with и декомпозиция методов в Delphi

У нас в команде запрещён к использованию оператор with. Основная причина в проблемах с надёжность кода с with. Существует и другая сторона работы с with. Часто его применение указывает на плохую организацию кода и переместив код в более адекватное место оператор with станет просто не нужен. Рассмотрим два примера.

Перемещение кода

Иногда with используется для формы или датамодуля чтобы установить свойства, возможно, вызывать несколько методов.

В таком случае лучше оформить весь блок кода внутри формы FormChart в виде метода. А вместо with сделать вызов этого метода. Ещё лучше когда у вызыващие формы есть специальный интерфейс (не в смысле типа в Delphi, а в смысле API) через который идёт работа с формой.

Декомпозиция функций

Задача — перебрать все записи в датасете. Код может быть примерно такой

Оператор with применяется к датасету чтобы не писать его название несколько раз. В тоже самое время этот оператор создаёт лишнюю вложенность, затрудняет чтение, особенно если смотреть только diff в svn. В такой ситуации метод можно разделить на два: один проходит цикл по датасету, другой обрабатывает отдельную запись.

В метод ProcessOneRow можно даже не передавать весь датасет а только нужные поля. Таким подходом значительно уменьшается вложенность, with становится не нужен.

Если вы нашли ошибку, пожалуйста, выделите фрагмент текста и нажмите Ctrl+Enter.

Оператор with и декомпозиция методов в Delphi: 4 комментария

  1. with удобен, когда функция возвращает экземпляр объекта и нам нужно с ним немного поработать, но мы не управляем жизненным циклом полученного объекта.
    Добавление колонки в TableView:
    with TableView.CreateColumn do
    begin
    Caption := …
    Visible := …
    DataBinding.ValueType := …

    end;
    Мы добавили столбик и дальше он живёт своей жизнью.
    А у вас, разработчик корчится «with нельзя», заводит переменную NewColumn, и если случай не такой очевидный, ещё где-то комментирует, что полученный экземпляр не нужно освобождать, поскольку не мы управляем его жизненным циклом. Это для тех, кому потом доведётся смотреть получившийся код в diff-ах…

    Единственное абсолютное правило — нет ни каких абсолютных правил 😉

    1. Спасибо, очень хороший и показательный пример проблемы которую выявляет with. Почему бы, например, не сделать процедуру которая принимает колонку и настраивает свойства?

      Вызов вместо with
      SetupColumn(TableView.CreateColumn …)

      Объявление процедуры может быть таким
      procedure SetupColumn(AColumn: TMyColumn … свойства )
      begin
      AColumn.Caption := …
      AColumn.Visible := …
      AColumn.DataBinding.ValueType := …

      Тем самым мы
      1. Выделяем код в один логический блок — функцию.
      2. Можем даже тестировать этот блок отдельно если применяется модульное тестирование
      3. Убираем лишний уровень вложенности

      1. И в вашем примере изящнее смотрелось бы
        procedure SetupColumn(AColumn: TMyColumn … свойства )
        begin
        with AColumn do
        begin
        Caption := …
        Visible := …
        DataBinding.ValueType := …
        end;

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *