Deutsch
Germany.ruФорумы → Архив Досок→ Программирование

​Сделать красиво?

317  
Murr патриот30.08.17 18:40
Murr
30.08.17 18:40 

Сделать красиво?


Есть код вида:


static TKnownRanges()
{
LiOrder.Kreis.NUM_KREIS.Table num_kreis = (LiOrder.Kreis.NUM_KREIS.Table)LiOrder.TLiOrderFactory.Create(LiOrder.TKnownTables.NUM_KREIS);
num_kreis.Load();
}

Фабрикой создается объект определенного типа.

Фабрикой, потому как там нужна дополнительная инициализация, доступ к элементам которой вне фабрики не желателен.

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

Объектов - много - 3х2х350 штук.


Вопрос - как сделать красиво, т.е. без кастинга?

#1 
dymanoid знакомое лицо30.08.17 19:27
dymanoid
NEW 30.08.17 19:27 
в ответ Murr 30.08.17 18:40, Последний раз изменено 30.08.17 19:28 (dymanoid)

Дженерики или вынести метод Load в общий интерфейс и юзать его.


Кстати: статический конструктор - зло. Убирай.

#2 
anly коренной житель30.08.17 20:01
anly
NEW 30.08.17 20:01 
в ответ dymanoid 30.08.17 19:27
статический конструктор - зло
почему зло?
Проклят нарушающий межи ближнего своего (Втор.27:17)
#3 
dymanoid знакомое лицо30.08.17 21:03
dymanoid
NEW 30.08.17 21:03 
в ответ anly 30.08.17 20:01, Последний раз изменено 30.08.17 21:06 (dymanoid)

В сети много инфы.

Если кратко:

  • время вызова статического конструктора недетерменировано (зависит от оптимизаций, среды выполнения и использующего кода)
  • во время вызова блокируются все другие потоки, кроме одного
  • все остальные статические методы и конструкторы класса работают медленнее (пусть на наносекунды, но в быстром цикле на много итераций это может сыграть роль)
  • ну и в добавок ограничивается нормальная lazy оптимизация с помощью флага beforefieldinit.
#4 
anly коренной житель31.08.17 00:00
anly
NEW 31.08.17 00:00 
в ответ dymanoid 30.08.17 21:03, Последний раз изменено 31.08.17 00:02 (anly)

по-моему первый и последний пункт противоречат друг другу. Ленивая инициализация (которая названа преимуществом) это ведь тоже - недетерминированный вызов (который назван недостатком)

Проклят нарушающий межи ближнего своего (Втор.27:17)
#5 
dymanoid знакомое лицо31.08.17 00:48
dymanoid
NEW 31.08.17 00:48 
в ответ anly 31.08.17 00:00, Последний раз изменено 31.08.17 00:59 (dymanoid)

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

И недетерминированность тут всё же немного разная. Для поля она более-менее предсказуемая. Перед первым использованием конкретного поля оно будет инициализировано. А вот с конструктором уже сложнее - или какое-то поле используется, или объект класса (если класс не статический) создаётся. Намного больше "недетерминированности".

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


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

#6 
Программист коренной житель31.08.17 08:24
NEW 31.08.17 08:24 
в ответ anly 30.08.17 20:01

статические переменные и функции - в принципе зло. хотябы только из-за того, что их сложно тестировать юнит-тестами :) а зачастую и невозможно.

#7 
dymanoid знакомое лицо31.08.17 09:12
dymanoid
NEW 31.08.17 09:12 
в ответ Программист 31.08.17 08:24

Не согласен насчёт статических методов. Сами по себе они окей, если не содержат состояния. Что-то типа Math.Min (). Вполне себе тестируемый.

#8 
MrSanders старожил31.08.17 09:29
NEW 31.08.17 09:29 
в ответ dymanoid 31.08.17 09:12

Я бы сказал что для тестов статические методы не страшны до тех пор пока они оперируют только своими параметрами и не создают новых объектов. Т.е. Math.Min() не страшен. А вот какой-нибудь File.CreateTemp(имя файла) - страшен если внутри он лезет к системным свойствам, выйсняет где временный каталог и создает там файл. Вернет нам файл и а него будет тест пихать, например, логи. Подменить такой файловый объект фейком сложно. Тестировать такое уже не так весело - на разных машинах временные каталоги могут быть разные.

Т.е. протестировать сам File.CreateTemp не сложно, а вот тестировать методы, которые его используют - вот где засада.

#9 
Murr патриот31.08.17 09:55
Murr
NEW 31.08.17 09:55 
в ответ dymanoid 30.08.17 19:27

Кстати: статический конструктор - зло.

------

Там табличка, однократно читаемая с диска. Можно сунуть в синглетон, но класс и так синглетон. Так что - без разницы.

#10 
Программист коренной житель31.08.17 09:55
NEW 31.08.17 09:55 
в ответ dymanoid 31.08.17 09:12

Если брать примитивные примеры, то проблем, конечно, меньше.


Статические функции нельзя перегрузить и сделать из них заглушки и если для метода Math.Min (int a, int b) это не представляет больших проблем, но если статическая функция затрагивает внешнюю среду, то все становится не так красиво.


У меня на прошлом проекте коллега очень любил статические функции. И это был пипец, там вложенность вызовов была где-то 10 уровней. К тому же добавился анализатор кода, который говорил, что если функция не использует поля класса, то ее надо делать статической. Надо ли говорить, что проект тот был практически нетестируем? :)

#11 
Murr патриот31.08.17 10:06
Murr
NEW 31.08.17 10:06 
в ответ dymanoid 30.08.17 19:27

Дженерики или вынести метод Load в общий интерфейс и юзать его.

------

Не уверен, что получится с генериками - в объектах не совсем шаблонный код.

Тот же Лоад() - их много.

Первый - без параметров - загружает всю таблицу,

Второй - с параметром - первичный ключ таблицы - загружает единичную строку.

Третий и дале - с параметрами фореин кей - загружают отфильтрованные наборы.

Иногда в третьей группе совпадают количество и типы полей в индексе - надо добавлять поле или делать список-класс...


Можно, конечно, попробовать эллипсис или замену, но мне больше хочется понимать что происходит и иметь ошибку времени компиляции... бо, слишком много кода.

#12 
Murr патриот31.08.17 10:18
Murr
NEW 31.08.17 10:18 
в ответ dymanoid 31.08.17 00:48

Преимущество ленивой инициализации полей - быстродействие.

-----

Не всегда.

Я как-то получил провал в быстродействии.

Дело было так - на сервер отправлялся запрос и там он считался минут 10-15.

В паралель шла инициализация всего-чего-там-надо-инитить...

Ну а с Лази - инициализация была переложена на после получения ответа... в результате еще минуты полторы все ждало окончания процесса.


Всякие синглтоны и иже с ними.

-----

Да. Только в данном конкретном случае Я не могу перевести табличку в синглетон.

Чтобы это сделать надо существенно поменять ДАЛ-уровень именно для этой таблички.

Иметь же на ДАЛ-уровне ДВА разных класса объектом мне категорически не хочется.

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

Как-то так.



Вопрос со статическим конструктором и полем меня на сейчас не беспокоит - его можно поправить когда захочется.

Меня интересует упрощение конструкции с фабрикой.

#13 
dymanoid знакомое лицо31.08.17 10:19
dymanoid
NEW 31.08.17 10:19 
в ответ Программист 31.08.17 09:55

Я про Фому, а мне про Ерёму. Какая разница, File.Create() или new File().Create()? Что статический, что не статический - если метод с состоянием или с побочными эффектами, то оба плохо тестируемы. А если используется IoC и нет состояния, то оба типа отлично тестируются.


Я хотел сказать, что статические методы в принципе - не зло. Просто их надо правильно готовить. А вот статическое состояние в 99% - зло.

#14 
dymanoid знакомое лицо31.08.17 10:21
dymanoid
NEW 31.08.17 10:21 
в ответ Murr 31.08.17 10:18

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

#15 
Murr патриот31.08.17 11:09
Murr
NEW 31.08.17 11:09 
в ответ dymanoid 31.08.17 10:21

твой код - наиотвратнейшее говно.

-----

А Я разве спорю?


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

Кода - много - порядка 2 Гб,


Один проход - т.е. однократное вычисление интересующих пользователя данных в оригинальном варианте занимает 40 минут.

Кое-что Я поправил - нарезал код на классы, оптимизировал некоторые операции - начальная загрузка сокращена с 4-5 минут (время ответа сервера) и последующего отбора (3-4 минуты) до 15-20 секунд. Но все же не все нарезано или разделено правильно - полную задачу-то Я не знаю, доков - нет. Все надо вынимать из кода.


Сейчас борюсь со следующим этапом обсчета - там 99.5% времени занимает выполнение стандартного вызова ДатаТабле.Селект() с детализацией для каждой обрабатываемой детальки. Остальное - обсчет под единицы оборудования с учетом вариантности загрузки оборудования. Вместе с логами и дампами - около 6 часов счета. Если уберу логи и дампы все одно останется полчаса счета. Надо - 3-5 секунд.

И сделать надо всего 2 вещи - избавится от Селекта выполнив счет за один проход... и... сделать код расчета сменяемым вместе со сменой оборудования.


Это - по текущей задаче. Есть еще три, не считая всякой мелочи.

Одна - точно такая же как первая - она собирает исходные данные для обсчета текущей.

Вторая - импортит в систему заказы клиентов (каждый - в своем формате).

Третья - отчеты - там тоже все в стиле ВБ6-лике, но АСПХ-имплементация.

Ковыряю все четыре в параллели... один... естественно - код - гамно галимое и даже выдержать имплементацию в одном стиле - проблемно.

Но - работаю, кое-что меняется к лучшему.


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

Один из примеров избыточного кода - неудобно-длинная операция создания таблички.

Идеи как сделать более удобный вариант - всегда обсуждаемо.

#16