Каталог решений - Логические выражения и красивый код

Логические выражения и красивый код

Логические выражения и красивый код

В наличии

В данной статье я хочу поделиться своей практикой применения логических выражений при написании кода. Учитывая тот факт, что платформа 1С 8.х использует сокращенный цикл вычисления логических выражений, можно заменить громоздкие конструкции “Если Тогда ИначеЕсли КонецЕсли” на красивую и лаконичную запись, похожую на список операций.

Категория:

Описание

Вначале изложу немного теории относительно вычисления логических выражений. То, что будет написано в первом разделе, есть в любом самоучителе по любому современному языку программирования. И если вам покажется, что я описываю “элементарные вещи, которые и так все знают”, то можете смело пропустить первый раздел.

Любое выражение, написанное в коде вычисляется слева направо и согласно приоритету операторов. При вычислении логических выражений приоритет операторов следующий (в порядке убывания):

  • Операции сравнения (=, >, <, <>)

  • НЕ

  • И

  • ИЛИ

Три логических оператора: НЕ И ИЛИ для удобства понимания можно представить как арифметические: унарный минус, умножить, плюс (соответственно). Например, если мы хотим посчитать сумму покупок: 5 яблок по 12 рублей, 3 килограмма гречки по 50 рублей, 2 рулона туалетной бумаги по 25 рублей — запишем в калькулятор все это одной строкой в естественном порядке и без всяких скобок: 5 * 12 + 3 * 50 + 2 * 25. Ведь еще в школе нас научили, что сначала множим, потом плюсуем. Так и здесь мы сначала получим сумму каждой позиции, а затем общую сумму.

Аналогично работает приоритет в логическом выражении. Сначала будут вычислены все И, затем все ИЛИ. Раньше всех применится НЕ, оно инвертирует результат выражения справа от себя, аналогично унарному минусу: -5 — это как 5 только в другую сторону от нуля).

Операторы И и ИЛИ являются бинарными, то есть сравнивают 2 выражения слева и справа от себя и возвращают результат сравнения: Истина или Ложь. Цепочка операторов обрабатывается слева направо. При этом работает сокращенный цикл вычисления логических выражений. Такую фишку добавили в платформе 1с 8. В учебнике по javascript я вычитал замечательную аллегорию на этот механизм:

"Оператор И спотыкается на лжи, а оператор ИЛИ спотыкается на правде”.

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

А теперь практический пример.

Рассмотрим задачу загрузки элемента справочника “Номенклатура” из внешнего источника. Алгоритм действия примерно такой:

  • Создать карточку номенклатуры

  • Создать единицы измерения

  • Записать базовую единицу измерения в карточку номенклатуры

  • Загрузить штрихкоды номенклатуры

  • Загрузить цены номенклатуры.

Простой линейный алгоритм. При этом выполняться он должен именно в этой последовательности. И кроме того должен прерываться, если очередной этап выдал сбой. При этом желательно в конце вернуть общий результат выполнения операции. Мы можем оформить каждый этап в отдельную функцию, которая в зависимости от успешности возвращает Истину или Ложь, а затем написать следующий код:

Если НЕ СоздатьКарточкуНоменклатуры() Тогда
   Возврат Ложь;
КонецЕсли;
Если НЕ СоздатьЕдиницыИзмерения() Тогда
   Возврат Ложь;
КонецЕсли;
Если НЕ ЗаписатьБазовуюЕдиницу() Тогда
   Возврат Ложь;
КонецЕсли;
Если НЕ ЗагрузитьШтрихкоды() Тогда
   Возврат Ложь;
КонецЕсли;
Если НЕ ЗагрузитьЦены() Тогда
   Возврат Ложь;
КонецЕсли;

Возврат Истина;

 

 

Вроде получилось наглядно и понятно. Но смущает часто повторяющиеся блоки Если Тогда КонецЕсли. Теперь вспомним теорию: как себя ведет цепочка И при вычислении, и перепишем код следующим образом:

Возврат СоздатьКарточкуНоменклатуры()
	И СоздатьЕдиницыИзмерения()
	И ЗаписатьБазовуюЕдиницуИзмерения()
	И ЗагрузитьШтрикоды()
	И ЗагрузитьЦены();

 

 

Код получился значительно короче, при этом сохранил прежний функционал. Выполнение будет происходить в том же порядке и прервется на той функции, которая вернет Ложь.

 

Теперь немного усложним задачу. У нас есть разная номенклатура с характеристиками и без, весовая и штучная. Для номенклатуры с характеристиками надо загружать характеристики номенклатуры, для весовой — коды весового товара. В этом случае мы из внешнего источника получаем булевы признаки: ИспользуютсяХарактеристики и ВесовойТовар. Теперь самая длинная цепочка алгоритма должна выглядеть так:

  • Создать карточку номенклатуры

  • Создать единицы измерения

  • Записать базовую единицу измерения

  • Создать характеристики

  • Загрузить коды весового товара

  • Загрузить штрикоды

  • Загрузить цены

Алгоритм перестал быть линейным. Набор операций теперь зависит от флагов: ИспользуютсяХарактеристики и ВесовойТовар. Попробуем записать этот алгоритм в одну строчку:

Возврат СоздатьКатрочкуНоменклатуры()
	И СоздатьЕдиницыИзмерения()
	И ЗаписатьБазовуюЕдиницуИзмерения()
	И (НЕ ИспользуютяХарактеристики ИЛИ СоздатьХарактеристики())
	И (НЕ ВесовойТовар ИЛИ ЗагрузитьКодыВесовогоТовара())
	И ЗагрузитьШтрихкоды()
	И ЗагрузитьЦены();

Для замены конструкции:

Если ИспользуютсяХарактеристики Тогда
	Если НЕ СоздатьХарактеристики() Тогда
		Возврат Ложь;
	КонецЕсли;
КонецЕсли;

 

 

Мы использовали конструкцию с ИЛИ. Поскольку мы помним, что ИЛИ запинается на правде, значение флага инвертировали с помощью НЕ. Такое выражение остановится на вычислении значения флага, если он не установлен либо пройдет дальше и вычислит правое выражение и создаст характеристики для товара. Поскольку приоритет ИЛИ ниже, чем И, то эту конструкцию мы заключили в скобки.

Чтобы избавиться от круглых скобок, можно перевернуть все выражение и заменить И на ИЛИ так чтобы вложенные выражения содержали конструкцию И и выполнялись согласно приоритету первыми:

Результат = НЕ СоздатьКарточкуНоменклатуры()
	ИЛИ НЕ СоздатьЕдиницыИзмерения()
	ИЛИ НЕ ЗаписатьБазовуюЕдиницуИзмерения()
	ИЛИ ИспользуютсяХарактеристики
		И НЕ СоздатьХарактеристики()
	ИЛИ ВесовойТовар
		И НЕ ЗагрузитьКодыВесовогоТовара()
	ИЛИ НЕ ЗагрузитьШтрихкоды()
	ИЛИ НЕ ЗагрузитьЦены();

Возврат НЕ Результат;

Поскольку ИЛИ запинается на правде, то для сохранения функционала мы инвертировали каждый вызов операции. Вложенное условие с конструкцией И выполняется в первую очередь, поэтому круглые скобки уже не нужны. Поскольку И запинается на Лжи, то при снятом флаге ИспользуютсяХарактеристики выражение НЕ СоздатьХарактеристики() вычисляться не будет, и соответственно характеристики не создадутся. В таком виде вложенное выражение читается естественнее. Все полученное выражение возвращает Ложь в случае успешного выполнения всех операций, поэтому значение результата в конце инвертируется. Кстати дополнительный отступ перед И визуально отделяет вложенное условие, что в условии отсутствия круглых скобок облегчает анализ кода.

has been added to your cart:
Оформление заказа