ООП. Инкапсуляция, часть 3.

12.12.08

Разработка - Математика и алгоритмы

Заключительная серия размышлений об инкапсуляции в 1С.


Более сложный пример инкапсуляции.

В каталоге плохих запахов кода Мартина Фаулера есть такой запах, который называется
"Связанные данные" (Data clumps).

Начинающие рефактореры редко обращают на него внимание, и очень зря. Ибо для того,
чтобы научиться писать хороший обектно-ориентированный код нужно выработать
особенно тонкое чутье к этому запаху. Ибо он устраняется с помощью рефакторинга
"Выделение класса" (Extract class).

Что это такой за запах?

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

Нужно ИНКАПСУЛИРОВАТЬ эти данные в класс.

А методы, в которые эти данные передавались как параметры - станут первыми кандидатами
на то, чтобы стать методами данного класса.

Ведь что такое класс в самом общем смысле этого слова? Это некоторые данные, и методы
работы с ними. Данные первичны.

Пример.

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

Соответственно, у нас есть плотная связка данных: Менеджер + Месяц. И пара методов для
работы с ними: КВПП_Общий() и КВПП_Бренда(Бренд). Обратите внимание, мне нет надобности
передавать в свои методы менеджера и месяц в качестве параметров. Эти данные уже там
есть. Они инкапсулированы в классе.

Даже создание таких маленьких классов (два параметра и два метода) позволяет довольно
сильно разгрузить код от подробностей. А говорят, что иногда такие наборы данных
могут довольно сильно разрастись, и что в таком случае подобная инкапсуляция - это
верное средство от расстройства рассудка. Охотно верю.

См. также

Математика и алгоритмы Программист Платформа 1C v8.2 Конфигурации 1cv8 Россия Абонемент ($m)

На написание данной работы меня вдохновила работа @glassman «Переход на ClickHouse для анализа метрик». Автор анализирует большой объем данных, много миллионов строк, и убедительно доказывает, что ClickHouse справляется лучше PostgreSQL. Я же покажу как можно сократить объем данных в 49.9 раз при этом: 1. Сохранить значения локальных экстремумов 2. Отклонения от реальных значений имеют наперед заданную допустимую погрешность.

1 стартмани

30.01.2024    2748    stopa85    12    

36

Математика и алгоритмы Бесплатно (free)

Разработка алгоритма, построенного на модели симплекс-метода, для нахождения оптимального раскроя.

19.10.2023    6705    user1959478    50    

36

Математика и алгоритмы Разное Платформа 1С v8.3 Конфигурации 1cv8 Россия Абонемент ($m)

Расширение (+ обработка) представляют собою математический тренажер. Ваш ребенок сможет проверить свои знание на математические вычисление до 100.

2 стартмани

29.09.2023    2684    maksa2005    8    

25

Математика и алгоритмы Инструментарий разработчика Программист Платформа 1С v8.3 Мобильная платформа Россия Абонемент ($m)

Что ж... лучше поздно, чем никогда. Подсистема 1С для работы с регулярными выражениями: разбор выражения, проверка на соответствие шаблону, поиск вхождений в тексте.

1 стартмани

09.06.2023    10242    7    SpaceOfMyHead    18    

61

Математика и алгоритмы Программист Платформа 1С v8.3 Конфигурации 1cv8 Бесплатно (free)

Три задачи - три идеи - три решения. Мало кода, много смысла. Мини-статья.

03.04.2023    3959    RustIG    9    

25

Механизмы платформы 1С Математика и алгоритмы Программист Платформа 1С v8.3 Россия Бесплатно (free)

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

23.11.2022    3075    gzharkoj    14    

24

Математика и алгоритмы Программист Платформа 1С v8.3 Россия Абонемент ($m)

Обычно под распределением понимают определение сумм пропорционально коэффициентам. Предлагаю включить сюда также распределение по порядку (FIFO, LIFO) и повысить уровень размерности до 2-х. 1-ое означает, что распределение может быть не только пропорциональным, но и по порядку, а 2-ое - это вариант реализации матричного распределения: по строкам и столбцам. Возможно вас заинтересует также необычное решение этой задачи через создание DSL на базе реализации текучего интерфейса

1 стартмани

21.03.2022    8889    7    kalyaka    11    

44
Комментарии
Подписаться на ответы Инфостарт бот Сортировка: Древо развёрнутое
Свернуть все
1. fez 46 12.12.08 02:00 Сейчас в теме
2. O-Planet 6441 12.12.08 06:50 Сейчас в теме
Нююю... К третьей части тема раскочегарилась. Имхо, автор ввел по-большому счету свое понимание, и даже почти свое определение инкапсуляции в этой серии статей. Оно не стандартное, и это - смелый ход. Если тему развить соответствующим образом, то, возможно, оно и имеет право на жизнь. Считаю, что минусом статей является нечеткое позиционирование, что все описанное не относится к стандартной 1С, а к ее расширению в 1С++. Но скомпенсирую свой минус по первой статье плюсом. Строг. Потому что про ООП очень люблю читать и обсуждать. Я бы про ООП в 1С написал все не так. Начал бы от стандартной 1С и реализации ООП в ней, а потом бы перешел на 1С++.
3. artbear 1562 12.12.08 06:55 Сейчас в теме
(2) Цитата: "Начал бы от стандартной 1С и реализации ООП в ней"
В штатном 1С, собственно, нет ООП :)
Точнее так - сами внутренности 1С построены на ООП, для клиентского кода предоставляются спец.объекты ООП, но нет возможности создавать собственные классы/объекты и именно это не дает 1С считаться ООП-средой или языком :(

PS я также люблю порассуждать/почитать/пообсуждать по ООП, рефакторингу, построению кода :)
5. fez 46 12.12.08 12:48 Сейчас в теме
(2) Про позиционирование.
Считаю, что 1С++ уже достаточно давно присутствует на рынке. Так что можно считать, что все интересующиеся ООП, применительно к 7.7, уже давно знают, что использование 1С++ является самым простым и эффективным способом получить это самое ООП в этих самых 7.7. И не просто знают - для них это очевидно и естественно.

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

Хотя может быть ты и прав, и можно было бы одной фразой упомянуть об этом в самом начале.
15. O-Planet 6441 12.12.08 23:27 Сейчас в теме
(2) >> В штатном 1С, собственно, нет ООП :)
>> Точнее так - сами внутренности 1С построены на ООП, для клиентского кода предоставляются спец.объекты ООП, но нет возможности создавать собственные классы/объекты и именно это не дает 1С считаться ООП-средой или языком :(

А вот тут, почитав эту подборку статей, не согласен. Если пользоваться терминологией автора и рассматривать упрятывание чего-либо в глобальную функцию с осмысленным названием, как инкапсуляцию, то под созданием собственных классов по праву можно понимать создание собственных документов на базовом классе "Документ". Чем не механизм наследования? Соответственно, копии моего класса - это реальные доки, созданные в пользовательском режиме. А вот полиморфизм надо еще поискать в версии 7.7...
16. fez 46 13.12.08 06:15 Сейчас в теме
(15) А чего там искать? Документ.Провести(). Интерфейс одинаковый, поведение разное. Заказывали полиморфизм? Получите-распишитесь.
17. O-Planet 6441 13.12.08 20:53 Сейчас в теме
(16) Вообще, да. Короче, любой предопределенный метод.
4. JohnyDeath 302 12.12.08 10:16 Сейчас в теме
А сами методы КВПП_Общий() и КВПП_Бренда(Бренд) можно как-то подробнее описать?
6. fez 46 12.12.08 12:52 Сейчас в теме
(4) Вот весь код класса. Методы почему-то не КВПП*, а КВПО*, но это неважно :)

===============================
Перем НачалоМесяца, КонецМесяца;

Перем КэшКВПО;

Перем Менеджер;

Процедура __Инит__(ВыбДата, ВыбМенеджер) Экспорт

НачалоМесяца = НачМесяца(ВыбДата);
КонецМесяца = КонМесяца(ВыбДата);

Менеджер = ВыбМенеджер;

КэшКВПО = "Не посчитан";

КонецПроцедуры


Функция КВПО_Бренда(Бренд) Экспорт

Если Бренд = Константа.БрендБезПлана Тогда
Возврат 1; // Bug 3973
КонецЕсли;
Если Бренд = Константа.БрендКонсультации Тогда
Возврат 1; // Bug 3976
КонецЕсли;
Если Бренд = Константа.БрендРаспродажа Тогда
Возврат 1; // Bug 4223
КонецЕсли;

Период = СоздатьОбъект("Справочник.ПериодыПланирования");
Если Период.НайтиПоРеквизиту("НачДата", НачалоМесяца, 1) = 0 Тогда
Возврат 1;
КонецЕсли;

ПП = СоздатьОбъект("Справочник.ПланыПродаж");
ПП.ИспользоватьВладельца(Период.ТекущийЭлемент());
ПП.ВыбратьЭлементыПоРеквизиту("Менеджер", Менеджер, 1, 0);
Пока ПП.ПолучитьЭлемент() = 1 Цикл
Если ПП.Бренд = Бренд Тогда
Если ПП.РучнаяПравка = 1 Тогда
Возврат ПП.ИзмененныйКоэффициентВыполнения;
КонецЕсли;

Возврат глКоэффициентБренда(ПП.ПлановаяСуммаПродаж, ПП.ДостигнутаяСуммаПродаж);
КонецЕсли;
КонецЦикла;

Возврат 1;
КонецФункции

Функция РассчитатьКВПО_Общий() Экспорт
Период = СоздатьОбъект("Справочник.ПериодыПланирования");
Если Период.НайтиПоРеквизиту("НачДата", НачалоМесяца, 1) = 0 Тогда
Возврат 1;
КонецЕсли;

СуммаПлана = 0;
СуммаРезультата = 0;

ПП = СоздатьОбъект("Справочник.ПланыПродаж");
ПП.ИспользоватьВладельца(Период.ТекущийЭлемент());
ПП.ВыбратьЭлементыПоРеквизиту("Менеджер", Менеджер, 1, 0);
Пока ПП.ПолучитьЭлемент() = 1 Цикл
Если (ПП.Бренд = Константа.БрендБезПлана) И
(ПП.РучнаяПравка = 1) Тогда
Возврат ПП.ИзмененныйКоэффициентВыполнения;
КонецЕсли;

СуммаПлана = СуммаПлана + ПП.ПлановаяСуммаПродаж;
СуммаРезультата = СуммаРезультата + ПП.ДостигнутаяСуммаПродаж;
КонецЦикла;

Если СуммаПлана = 0 Тогда
Возврат 1;
КонецЕсли;
Если СуммаРезультата / СуммаПлана > 0.8 Тогда
Возврат 1;
КонецЕсли;

Возврат 0;
КонецФункции

Функция КВПО_Общий() Экспорт

Если КэшКВПО = "Не посчитан" Тогда
КэшКВПО = РассчитатьКВПО_Общий();
КонецЕсли;
Возврат КэшКВПО;

КонецФункции
7. fez 46 12.12.08 12:57 Сейчас в теме
а в комментарий как-нибудь можно отформатированный код засунуть?
8. artbear 1562 12.12.08 13:08 Сейчас в теме
(7) Как обычно, [code1] и [/code1] - 1 убрать :)
9. fez 46 12.12.08 14:21 Сейчас в теме
Код
Перем НачалоМесяца, КонецМесяца;

Перем КэшКВПО;

Перем Менеджер;

Процедура __Инит__(ВыбДата, ВыбМенеджер) Экспорт
   
   НачалоМесяца = НачМесяца(ВыбДата);
   КонецМесяца = КонМесяца(ВыбДата);
   
   Менеджер = ВыбМенеджер;
   
   КэшКВПО = "Не посчитан";
   
КонецПроцедуры

   
Функция КВПО_Бренда(Бренд) Экспорт

   Если Бренд = Константа.БрендБезПлана Тогда
      Возврат 1; // Bug 3973
   КонецЕсли;
   Если Бренд = Константа.БрендКонсультации Тогда
      Возврат 1; // Bug 3976
   КонецЕсли;
   Если Бренд = Константа.БрендРаспродажа Тогда
      Возврат 1; // Bug 4223
   КонецЕсли;
   
   Период = СоздатьОбъект("Справочник.ПериодыПланирования");
   Если Период.НайтиПоРеквизиту("НачДата", НачалоМесяца, 1) = 0 Тогда
      Возврат 1;
   КонецЕсли;
   
   ПП = СоздатьОбъект("Справочник.ПланыПродаж");
   ПП.ИспользоватьВладельца(Период.ТекущийЭлемент());
   ПП.ВыбратьЭлементыПоРеквизиту("Менеджер", Менеджер, 1, 0);
   Пока ПП.ПолучитьЭлемент() = 1 Цикл
      Если ПП.Бренд = Бренд Тогда
         Если ПП.РучнаяПравка = 1 Тогда
            Возврат ПП.ИзмененныйКоэффициентВыполнения;
         КонецЕсли;
         
         Возврат глКоэффициентБренда(ПП.ПлановаяСуммаПродаж, ПП.ДостигнутаяСуммаПродаж);
      КонецЕсли;
   КонецЦикла;
   
   Возврат 1;
КонецФункции

Функция РассчитатьКВПО_Общий() Экспорт
   Период = СоздатьОбъект("Справочник.ПериодыПланирования");
   Если Период.НайтиПоРеквизиту("НачДата", НачалоМесяца, 1) = 0 Тогда
      Возврат 1;
   КонецЕсли;
   
   СуммаПлана = 0;
   СуммаРезультата = 0;
   
   ПП = СоздатьОбъект("Справочник.ПланыПродаж");
   ПП.ИспользоватьВладельца(Период.ТекущийЭлемент());
   ПП.ВыбратьЭлементыПоРеквизиту("Менеджер", Менеджер, 1, 0);
   Пока ПП.ПолучитьЭлемент() = 1 Цикл
      Если (ПП.Бренд = Константа.БрендБезПлана) И
          (ПП.РучнаяПравка = 1) Тогда
         Возврат ПП.ИзмененныйКоэффициентВыполнения;
      КонецЕсли;
      
      СуммаПлана = СуммаПлана + ПП.ПлановаяСуммаПродаж;
      СуммаРезультата = СуммаРезультата + ПП.ДостигнутаяСуммаПродаж;
   КонецЦикла;
   
   Если СуммаПлана = 0 Тогда
      Возврат 1;
   КонецЕсли;
   Если СуммаРезультата / СуммаПлана > 0.8 Тогда
      Возврат 1;
   КонецЕсли;
   
   Возврат 0;
КонецФункции

Функция КВПО_Общий() Экспорт
    
   Если КэшКВПО = "Не посчитан" Тогда
      КэшКВПО = РассчитатьКВПО_Общий();
   КонецЕсли;
   Возврат КэшКВПО;
   
КонецФункции
Показать полностью
10. fez 46 12.12.08 14:22 Сейчас в теме
11. vde69 925 12.12.08 18:16 Сейчас в теме
ну плюсану, тоже в качестве баланса за минус в первой части.

тем-не менее есть одно маленькое замечание/вопрос:
1с++ нарушаеть лицензионные соглашение ?????

ИХМО - нарушает, по этому и не так 1с++ распространена.

ps
статья - ни о чем, по сколько в ней изложены основы которые и так всем понятны, но мало примеров реализации. Короче можно было бы все обьеденить в одну, и еще добавить столько-же. Кроме того кто не пользует 1с++ она вообще имет только теоретический смысл...
12. fez 46 12.12.08 19:31 Сейчас в теме
(11) Практика показывает, что как раз с основами самые большие проблемы и возникают :)

И отвечу маленьким вопросом на маленький вопрос. А у 7.7 разве есть лицензионное соглашение? Дадите почитать?
13. vde69 925 12.12.08 19:54 Сейчас в теме
(11) у Альфа спрашивай, он от туда цитировал чего-то.
Кстати видимо и его защита тоже попадает :)

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

зы
кстати например я ни разу 1с++ не юзал (это к вопросу о распространенности). Хотя конечно ООП мне знакомо не по наслышки.
14. fez 46 12.12.08 22:10 Сейчас в теме
(13) Про большую статью. Это много времени надо. Особенно чтобы вывод написать. А так есть несколько маленьких разрозненных мыслей - почему бы с обществом и не поделиться?

Поскольку мне понравилась реакция читателей - я намерен продолжать. Про полиморфизм мне всяко есть чего сказать. Ну и про наследование тоже наскребу наверное немного.
18. пользователь 14.12.08 00:08
Сообщение было скрыто модератором.
...
19. fez 46 14.12.08 19:09 Сейчас в теме
(18) Я их передаю как параметр один раз - в метод __Инит__(). В 1С, к сожалению, нет конструкторов с параметрами, поэтому приходится немного извращаться.
22. пользователь 14.12.08 19:12
Сообщение было скрыто модератором.
...
23. пользователь 14.12.08 19:13
Сообщение было скрыто модератором.
...
Оставьте свое сообщение