Как называется паттерн который принимает решения?

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

Підписуйтеся на Telegram-канал «DOU #tech», щоб не пропустити нові технічні статті

👍ПодобаєтьсяСподобалось0
До обраногоВ обраному0
LinkedIn

Найкращі коментарі пропустити

Думаю подойдут следующие паттерны:
1) Стратегия ( en.wikipedia.org/wiki/Strategy_pattern ). Это где собственно происходят расчеты.
2) «Конвейер» ( en.wikipedia.org/...of-responsibility_pattern ). Это если расчеты сложные и алгоритм зависит от многих «переключателей». Это будет цепочка из «стратегий», каждая из которых делает свои расчеты.
3) «Конструктор» ( en.wikipedia.org/wiki/Builder_pattern ). Он получает на вход кучу настроек из чекбоксов и внутри решает какие стратегии создать и добавить в конвейер.

Дозволені теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter
Дозволені теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter

Можливо, скажете мову программування? Чи вас з людиною познайомити треаб?

Жына, не?

Не «жена», а «глава семьи» =)

Правильный менеджмент.

{-# LANGUAGE ExistentialQuantification #-}

import Control.Applicative ( (<$>)
                           , (<*>)
                           )
data CheckBox = CheckBox { a :: Bool
                         , b :: Bool
                         , c :: Bool
                         }
solver :: forall a. CheckBox -> a
solver = solve <$> a <*> b <*> c
  where
    solve True  True  True  = undefined
    solve True  False True  = undefined
    solve True  False False = undefined
    solve True  True  False = undefined
    solve False True  True  = undefined
    solve False False True  = undefined
    solve False False False = undefined
    solve False True  False = undefined

подходит состояние, а не стратегия
www.dofactory.com/net/state-design-pattern

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

и, кстати, сайтик рекомендую, это по сути книга Банды за бесплатно и в цифровом виде.

не зрозумів пояснення. За тими формачками з чекбоксами може бути що завгодно. В залежності від складності задачі і кількості коду треба приймати рішення. Якщо можно обійтися одную ф-цією в яку передати всі параметри то взагалі нема потреби в патернах. Якщо там треба сконструювати щось на основі великоі кількості параметрів то підійде патерн Builder. А якщо то все якось впливає на поведінку програми чи іі частини то можно дивитися в сторону патернів поведінки sourcemaking.com/...terns/behavioral_patterns

Почитайте щось на зразок
www.amazon.com/...eve-Holzner/dp/0471798541
і намагайтеся чітко формулювати думки/питання

Алгоритм называется.

Как называется шаблон который на основе данных принимает решение?
Мозг

Паттерн IFELSETHEN =)

Пост неуважения к разговаривающим на языке паттернов.

«Как называется ОБЪЕКТ, который принимает решения»

Паттерн — это повторяемые раз за разом попытки отдельных погромистов влепить означенный объект, к месту и не к месту. Судя по формулировке проблемы, не к месту.

Как называется паттерн который принимает решения?
Приниматель решений

Думатель. И неонка ещё нужна...

Насяйника! )))

конкурс на самый оригинальный ответ? мой вариант — паттерн «тыжпрограммист» xD

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

Например — утюг починить!

А тут задача не ясна.

Зачем сразу паттерны? Самое простое и расширяемое решение — заводите словарь, ключом в котором объект с состояниями чекбоксов, а значением — тип расчета. Это самое простое и легко расширяемое для большинства случаев решение. Плюс в том, что легко расширяется и нет связей между разными комбинациями чекбоксов. В этом же минус, если вдруг в задаче явно можно чекбоксы на группы разбивать и группы имеют отдельный смысл. Но для этого надо узнать задачу.

Если это дотнет, то обычный хеш-словарь — Dictionary<>. В классе, который будет использоваться как ключ, переопределяете GetHashCode и Equals. И профит.
Не нужно усложнять. Иногда структуры данных лучше паттернов.

Я сейчас примерно так и сделал, перечисление с типом расчета, а потом свичаю его просто в методе.

Да можно даже ифами. Можно свитч. Но лучше дикшинари.

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

Перечисление с типом расчета и свитч по нему — тоже не очень. Оверхед. Т.е. я так понял, что у вас есть словарь, значениями у котором тип (перечисление). А потом, зная тип, выбираете свитчем что делать.

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

а потім програми таких програмістів не влазять і в 16Гб оператівки. Для чого вам дікшинарі який зберігай значення/обьякти більшість з яких можливо ніколи і не будуть використані?

Звідки ви знаєте, що не будуть використані? По-перше, я так і писав, що задача не зрозуміла, тому я запропонував найпростіше рішення, якщо не відомі додаткові умови.
Таке рішення буде працювати зразу. Якщо пізніше виявиться проблема з комбінаторикою, тоді можна рефакторити і обирати краще рішення.

Наприклад, в даному випадку кількість элементів в дікшинарі дорівнює кількості різних об’єктів. А її можна моделювати, змінюючи тіло Equals. Тобто така структура данних дозволяє в теорії тримати рівно стільки функцій, скільки потрібно.
Звичайно, якщо будуть додаткові умови такі, що чекбокси залежні, то можна використовувати інші підходи. Незалежність чекбоксів — це більш простий підхід, краще зразу обирати такий. Тому що якщо відразу обирати підхід з неявними залежностями, то і код буде з залежностями, а значить його важче змінювати, розширяти.

Вот: www.piter.com/...rovaniya-na-platforme-net

Потрать 150 гривен и 5 часов времени чтобы прочитать 320 страниц.

ДОУ превращается в гугл...

В гугле вы бы не смогли написать этот комментарий.

написать то я смог, но он не сохранился...

Вы нагло врете или покажите видео как у вас не сохраняется.

Думаю подойдут следующие паттерны:
1) Стратегия ( en.wikipedia.org/wiki/Strategy_pattern ). Это где собственно происходят расчеты.
2) «Конвейер» ( en.wikipedia.org/...of-responsibility_pattern ). Это если расчеты сложные и алгоритм зависит от многих «переключателей». Это будет цепочка из «стратегий», каждая из которых делает свои расчеты.
3) «Конструктор» ( en.wikipedia.org/wiki/Builder_pattern ). Он получает на вход кучу настроек из чекбоксов и внутри решает какие стратегии создать и добавить в конвейер.

Впервые вижу название

«Конвейер»
для Chain-of-responsibility. Всегда нзывал его «Цепочка обязанностей»

Потому «Конвейер» и «Конструктор» в кавычках. Правильный перевод, конечно Цепочка обязанностей и Строитель.
Но я заметил что джунам гораздо проще объяснять паттерны подходящими аналогиями из реальной жизни. Поэтому Chain-of-responsibility я обычно объясняю как конвейер, по которому едет «деталь» — модель и «станки» — процессоры ее обрабатывают. Так же и конструктор: ведь он именно создает и собирает нужный набор связанных объектов (вроде пазла или Лего) — гораздо понятнее, чем «строит дерево объектов».

эдакий вы не патриот, Ланцюжок відповідальностей!

Поддерживаю, но название получается тупое. Такое же впрочем как и «цепочка ответственностей». Англицизм, калька.

В Украине более популярен другой паттерн: “Ланцюжок безвідповідальності!”
В просторечии именуемый “спихбол”. Куда бы не пришел: в поликлинику, в ЖЭК, в банк, в саппорт, в любую гос-организацию или вообще к любому сотруднику, который сидит на “ставке”: везде первым делом тебя попытаются отправить к кому-нибудь другому, под любым предлогом.
То же самое на гнилом проекте: как только вылез сложный баг на продакшине начинаются переасайны на кого-то другого под любым предлогом. Особенно если баг в принципе невозможно пофиксить: например таймауты от того что система просто не может тянуть такую нагрузку.

патерны шматерны
этож автомат Мура че тут думать- таблицу переходов реализуй...

Лепить стейт машину немножко оверхед в данном случае. Не самый простой и понятный способ решить данную задачу.

А разве это очень сложно?
В .NET даже есть такая не очень известная технология как Workflow Foundation, где её можно слепить в полпинка.

При чем тут сложно. Вопрос уместно ли? Или все же есть более удачные решения.

WWF немножечко не для того сделана, что бы лепить машины состояний. интеграция с WCF и возможность обработки воркфлоувов длительность которых может измеряться неделями на то намекают.
короче, это альтернатива/развитие business intelligence на сколько я понимаю. с wwf не работал, а вот в business intelligence развлекался по рабочим потребностям.

Где тут оверхед?

struct _i_hate_patterns[8]
{
    int (*func)();
} =
{
           /* cb0 cb1 cb2 */
    func0, /* off off off */
    func1, /* off off on */
    func2, /* off on off */
    func3, /* off on on */
    func4, /* on off off */
    func5, /* on off on */
    func6, /* on on off */
    func7, /* on on on */
};

#define CHECK_BOX0(state) (state<<0)
#define CHECK_BOX1(state) (state<<1)
#define CHECK_BOX2(state) (state<<2)

...
_i_hate_patterns[CHECK_BOX0(read_check_box0_state()) | CHECK_BOX1(read_check_box1_state()) | CHECK_BOX2(read_check_box2_state())  ].func();

Согласен, оверхед не совсем подходящее слово, если говорить о производительности. Вы считаете у Вас сильно читабельное решение?

Согласен, оверхед не совсем подходящее слово, если говорить о производительности.
Что может быстрее этого решения? Ни одной проверки, только линейный код.
Вы считаете у Вас сильно читабельное решение?
Вполне. Просто, лаконично, быстро.

А, Вы driver developer :)

_i_hate_patterns[CHECK_BOX0(read_check_box0_state()) | CHECK_BOX1(read_check_box1_state()) | CHECK_BOX2(read_check_box2_state()) ].func();

вот это совсем не просто и не лаконично, честно Вам скажу.

А, Вы driver developer :)
И что?
вот это совсем не просто и не лаконично, честно Вам скажу.
Темплейты тоже не просто и не лаконично в исходном коде, зато просто и лаконично в машинном коде.
И что?
Видимо то, что Вы не будете городить билдер конфигураторов стратегий принятия решений, а просто решите задачу, максимально производительно, с минимальной потребностью в ресурсах :)
вот это совсем не просто и не лаконично
это тело. интерфейс логики — сама структура с индексом, кодирующим состояние.
читается норм.
поиск простой.
модификация — без проблем.

Для упрощения читаемости тут нужно лишь выделить функции/методы для вычисления аргумента. Или просто переопределить макросы немного по другому и будет _i_hate_patterns[CHECK_BOX0 | CHECK_BOX1 | CHECK_BOX2].func(); Лаконичнее? Если ещё нет, то свести к _i_hate_patterns[CHECK_BOXES].func();

а автомат где? Тут только технически код похож на автомат, но нет хранения состояния и переходов из состояния в состояние.

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

Спасибо. Мне надо научиться четче излагать свои мысли.

а автомат где? Тут только технически код похож на автомат, но нет хранения состояния и переходов из состояния в состояние.
ru.wikipedia.org/wiki/Автомат_Мура

Я в курсе.

int (*func)()

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

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

инт возвращаемый — это новое состояние? И куда оно сохраняется? Переходов нет. Очень с натяжкой это можно называть автоматом, если представить себе что выполнения функций не меняют состояние (т.е. диаграмма только из циклов), а состояние меняет пользователь кликая на чекбоксах.
См. комбинационные автоматы, автоматы без памяти. В данном случае без разницы это автомат Мура или Мили. Если указывать полное название, то это будет «детерминированный конечный автомат Мура без памяти.»

интересно почему реализация через автомат людям кажется сложнее чем 100500 патернов навертеть а потом эти макороны мучительно отлаживать

ну вы даете с этим автоматом ))

Чисто формально да, если нет состояний, то можно сказать, что это один из частных случаев автоматов, с одним состоянием и петлей. Вот я и писал что с натяжкой. Хотя формально да, автомат (я образование не программиста получал, мог ошибаться).
Но только ж это бессмыслица в некотором роде. Потому что определение чего-либо должно «определять», т.е. ограничивать в чем-то множество объектов. Я так слегка представил, каким путем шли рассуждая в математике. Разбирали автоматы с состояниями, а потом для общности определили и в автоматы то, что не имеет состояний, как бы потому что оно можно сказать имеет одно состояние. Почему нет.

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

А раз всё автоматы, то на что этот код еще похож? На хештаблицы. Хеш создаете равномерный, когда чекбоксами включаете биты.

Ну ладно, пусть будет автомат )) Мне всё равно как это называть, решение годится. А паттерны — зло.

ну вот вы и узнали зачем люди учаться на програмистов
приходите к нам в финансы — вообще заколдобитесь

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

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

Так и я могу, чего там, даже пару накидать вариантов того же самого:
Haskell:

calc funcs n = 
        let l = length n
            index a = sum $ zipWith (\x y -> (2 ^ x) * y) [l - 1, l - 2 .. 0] a
         in funcs !! (index n)

J:

   funcs =: f0`f1`f2`f3`f4`f5`f6`f7
   calc =: funcs@.#.
Kод, написанный Mike Gorchak, не конечный автомат Мура без памяти. Пруф:
ru.wikipedia.org/wiki/Автомат_Мура
или очевиднее на формулах:
ofap.ulstu.ru/...ory_of_automats/part1.htm
Т.е. в автомате Мура выходной сигнал зависит только от состояния. В случае, если без памяти, это равносильно 1 состоянию. Т.е. автомат возвращал бы всегда одну и ту же константу.
Возможно это автомат Мили без памяти. Но тогда судя из формулы, с одним состоянием — это просто функция. Т.е. функция как черный ящик, не известно как реализованная. Я очень редко пишу функции, на этом надо обязательно заострять внимание. Да, выше в коде написана функция. Но там даже нет сигнатуры ее, хотя бы вот так надо было написать:
void calc(int cb1, int cb2, int cb3)
{
      _i_hate_patterns[cb1 | cb2 | cb3 ].func();
}

И в коде только строка void calc(int cb1, int cb2, int cb3) относилась бы хоть как-то к конечному автомату. Но даже сигнатуру надо довообразить. По факту там ни строчки кода к конечному автомату не относится. Нужно большое воображение, чтобы его там представлять.
А

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

«Для любого автомата Мура существует эквивалентный ему автомат Мили и наоборот. Любой автомат Мура путём добавления ряда внутренних состояний может быть преобразован в автомат Мили.»

Да, выше в коде написана функция. Но там даже нет сигнатуры ее, хотя бы вот так надо было написать:

OMFG, там код даже с ошибками написан, ибо это псевдо код.

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

А если провести с аналогию с рациональностью, то говорите ерунду.

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

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

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

Давайте так митинги утренние проводить:
— Чем сегодня заниматься будешь? Будешь писать конечный автомат или будешь писать конечный автомат?
— Надоело мне уже писать конечный автомат. Пожалуй я выберу конечный автомат.
— Хорошо. Только вопрос. Как тебе удается всегда выбирать что-то новое, даже когда совсем не остается выбора???

Вы пишете хештаблицу, а называете это конечным автоматом. Ну ок. Я сдаюсь, формально вы правы.

Но, если в конечные автоматы включать автоматы без памяти, то вообще, любая функция в принципе есть таким автоматом, поэтому нет смысла вообще что-то определять этим словом.
Мало того, какие функции, каждое сравнение в коде — есть комбинационный автомат. А все модули КС (комбинационная схема) данного автомата построены с помощью коньюнкций, дизьюнкций и отрицаний.
Давайте так митинги утренние проводить:
Сегодня я планирую написать 14 коньюнкций нормальных дизьюнкций и 12 отрицаний. Смешно звучит?
Вы пишете хештаблицу, а называете это конечным автоматом. Ну ок. Я сдаюсь, формально вы правы.
Только такой хеш называют не равномерным, а perfect hash. Сейчас вы путаете алоритмы и модели. Я реализовал комбинационный автомат с помощью хеш-таблицы с использованием совершенной хеш функции. В данном же случае — это ярковыраженный автомат, отчего Нестор Иванович его так прямо и назвал, а я тем не менее точно понял его мысль. Я ведь мог создать просто трёхмерный массив i_hate_patterns[2][2][2] и реализовать этот автомат просто доступ к элементам массива. Далее я опять мог согдать одномерный массив и реализовать доступ через страйды cb0+cb1*2+cb2*4, который, о чудо, опять выглядит как perfect hash. В общем по меньше заморачивайтесь, а дискреткой всё-таки займитесь :)

Ну да, идеальный хеш. Но вы поняли, что я хотел сказать. Равномерный, может и не пользуется как название, но подразумевается. Пишут, например так, что хорошим решением будет, когда хеш-функция выдает «случайные» значения. Подразумевают равномерное распределение. Т.е. в корзинках приблизительно одинаковое число значений. А идеальный хеш — частный случай — по одному.

Только не говорите, что корзинки называются ведерками или еще как-то )))

Пишут, например так, что хорошим решением будет, когда хеш-функция выдает «случайные» значения. Подразумевают равномерное распределение. Т.е. в корзинках приблизительно одинаковое число значений. А идеальный хеш — частный случай — по одному.
А если так: cb2<<7 | cb1<<5 | cb0 <<1 ? Распределение не равномерное, но хеш всё равно совершенный.
Т.е. в корзинках приблизительно одинаковое число значений

0 и 1, значения близкие. Если массив соорудите нужного размера.

0, 2, 32, 34, 128, 130, 160, 162. — где ж тут равномерное распределение?

Если брать бинарное распределение, то ~57% нулей и ~43% единиц.

а про корзинки вы читаете? если разница между количеством значений в корзинках единица — то это крутой хеш. Равномернее не бывает. К сожалению, числа с дробной частью количества значений не бывают.

а про корзинки вы читаете?
Читаю, но есть вероятность, что не понимаю. Теорией корзинок я не владею %)

Про паттерны поддерживаю. Но у меня с ними особые счеты ))

Если посмотреть на паттерны банды четырех, так большинство из них на одном и том же принципе написано, схемы очень похожи, только названия разные. Наследование и скрывание за предком или интерфейсом.

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

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

Паттерны никакого отношения к «думать о потом» не имеют. Это типовые решения типовых задач (обычно обусловленных недостаточным уровнем абстракций ЯП), имеющие собственные названия для облегчения коммуникаций. Сначала принимаешь решение нужно ли закладывать расширяемость, универсальность и прочие «потом», а уж потом, если надо, думаешь, как реализовать — с паттернами (если о них знаешь :)) или самостоятельно.

вот за такие штуки я и люблю доу

Чувствуется рука мастера, однако!
Ни добавить, ни отнять.

Очень смешно, когда народ на джаве реализует нечто похожее, но с использованием 100500 класов, билдеров, стратегии, и спринга для конструирования %)

Это если предположить, что чекбоксов 3, а автор сказал, что у него «куча», наверное это всеж больше 3-х.

Если, честно, то я очень сомневаюсь, что поведение кода будет сильно различным в зависимости от чекбоксов. Ну а если всё же различный код, то да, увеличивать размер массива.

а автор сказал, что у него «куча»
Хотелось бы напомнить, что там прогрессия и грызут сильные сомнения, что автору понадобиться обрабатывать все возможные состояния разным кодом.
Хотелось бы напомнить, что там прогрессия
Не совсем понял к чему это
грызут сильные сомнения, что автору понадобиться обрабатывать все возможные состояния разным кодом.
Скорее всего можно свести к последовательному выполнению набора функций над данными.
Не совсем понял к чему это
Сорри, квадратичная зависимость, конечно. Чекбоксы же бинарны.
Скорее всего можно свести к последовательному выполнению набора функций над данными
Либо к заполнению бинарного массива и использования по мере необходимости.
В любом случае — это уже автору думать зачем и когда эти данные использовать.

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

Тем, кто не считают этот код простым и читабельным я предлагаю написать простенькую особо читабельную функцию перевода числа (с диапазоном 1-3999) из десятичной системы счисления с арабскими цифрами в римскую систему счисления с латинскими цифрами для проведения публичного code review.

challenge accepted :)

python 2.7, код без проверок и на float сломается

roman_numbers = {
    1000:   'M',
    900:    'CM',
    500:    'D',
    400:    'CD',
    100:    'C',
    90:     'XC',
    50:     'L',
    40:     'XL',
    10:     'X',
    9:      'IX',
    5:      'V',
    4:      'IV',
    1:      'I',
}
roman_order = sorted(roman_numbers.keys(), reverse=True)

def dec_to_roman(num):
    result = []
    for divisor in roman_order:
        digits = num / divisor
        num -= digits * divisor
        result.append(roman_numbers[divisor] * digits)
    return ''.join(result)

# all numbers from 0 to 100 inclusive
[dec_to_roman(i) for i in xrange(101)]

UPD поправил инициализацию roman_order

Меня больше интересует как это напишут C/C++ программеры :) Выбора по сути два (или три, если смешать оба стиля) всего, либо спагетти-код (что сразу подводит резюме под квалификацией), либо «нечитаемый», как у меня и у вас :)

либо «нечитаемый», как у меня и у вас
Почему нечитаемый? Даже не зная питона, замечательно прочел вышеприведенный код, разве что подивившись несколько этой конструкции
roman_numbers[divisor] * digits
с точки зрения С-С++, но все равно ж понятно.

Разве я писал, что я считаю ваш код «нечитаемым»? Я сказал, что он не настолько простой, как вы говорите. Лично мне ваше решение понравилось. Но некоторым людям с таким кодом сложнее работать, чем с более тормозными/прожорливыми, но более читабельными альтернативами.

Есть ещё третий вариант. Читаемый, удобный, сопровождаемый код, но при этом с оверхедом в плане быстродействия и/или памяти (чаще всего — и того, и другого).

Конкретно насчёт вашего задания: вот мой «перевод» с Python на C++ кода Andy Wilk. Быстро? Ни в коем случае, в performance-critical участках приложения так писать недопустимо (но мы помним, что не все участки кода должны быть оптимизированы до zero overhead). Читабельно? Очень даже.

ideone.com/gabnpi

upd.: конкретно в этом случае вместо map можно вообще юзнуть обычный вектор ideone.com/NZCqEI
или даже built-in массив ideone.com/iWgq9E

или даже built-in массив ideone.com/iWgq9E
#include <stdio.h>

const char* ones[10]={"", "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX"};
const char* tens[10]={"", "X", "XX", "XXX", "XL", "L", "LX", "LXX", "LXXX", "XC"};
const char* hundreds[10]={"", "C", "CC", "CCC", "CD", "D", "DC", "DCC", "DCCC", "CM"};
const char* thousands[10]={"", "M", "MM", "MMM", "", "", "", "", "", ""};

void dec_to_roman(int val)
{
    fprintf(stdout, "%s", thousands[val/1000]); val%=1000;
    fprintf(stdout, "%s", hundreds[val/100]); val%=100;
    fprintf(stdout, "%s", tens[val/10]); val%=10;
    fprintf(stdout, "%s\n", ones[val]);
}

int main()
{
   for (int it=1; it<101; it++)
   {
       dec_to_roman(it);
   }

   return 0;
}

А вот так уже нечитабельно?

Для кого-то может и да, не знаю. Лично для меня оба варианта вполне читабельны. «Питонячий» немного легче воспринимать. Но именно что «немного».

Я тоже склонялся сначала к примитивному конечному автомату. Но потом передумал.

почему? Чем лучше problem factory городить?

Так state паттерн это и есть примитивная стейт машина.

А при чем тут state паттерн вообще? :) Вроде никто не упоминал)

На ум приходит сразу 2 паттерна: стратегия и команда. Тут уж зависит от Вашей архитектуры.

Підписатись на коментарі