У задания есть тип, входные параметры и результат.
Тип это enum. Обработчик заданий берет десериализованное сообщение, в нем всегда есть поле с типом, и в большом switch доходит до ветки кода для этого конкретного типа сообщения, десериализует исходное сообщение ещё раз, уже в тип соответствующий типу задания и передаёт обработчику для этого типа заданий.
Теперь, предположим, я сделаю иначе. Я последую рекомендации вумных как вутка Фаулера и прочих любителей радикального ООП. Я создам класс с виртуальным методом и кучу его наследников, по одному для каждого типа задания.
Затем я сделаю словарь с ключом по типам сообщений, т.е. enum, и значением для ключа - наследником того класса. И буду для каждого сообщения создавать экземпляр соответствующего класса и вызывать тот самый виртуальный метод, в котором будет уже написана десериализация сообщения в нужный тип и вся последующая логика.
Но вот вопрос. Для нового типа задания мне будет нужен новое значение в enum. В первом варианте обработчика, со switch, я могу повесить прагму, которая будет выдавать ошибку компиляции, если некое значение enum отсутствует в одном switch. А в варианте с со словарём, виртуальным методом и Фаулером у меня не будет способа заставить компилятор проверить корректность моего кода. Я могу конечно написать тест, только вот тест - это не проверка компилятора, а нечто иное.
Итак, можно ли заставить компилятор проверять вариант с виртуальным методом? Как бы вы сделали? Заранее попрошу не писать про MassTransit и около, он тут мало применим.
Не понимаю, почему что то прописать в switch можно, а заполнение словаря нельзя. И не много не понятно, что именно хочешь ты от виртуального метода, что ты его проверяешь.
Хочу я вот чего: чтобы когда один человек пишет запускалку задания, чтобы этот же человек не забыл написать обработчик задания
не уверен что именно делать должно. Но для таких вариантов, мне кажется удобным система создания абстрактного класса который определяет 2 вещи. Как модель он несет сообщение - задание. И он же как инициатор задания определяет, как системе его обработать. Если это не большая логика, то в несколько делегатов можно запихнуть логику. Ну и наследоватся от абстрактного класса. Потом в одном месте ты их собираешь, и просто запускаешь. ничего искать по системе, где прописать, что забыл, не надо
Как модель несёт задание. А как оное задание будет сериализоваться и десериализоваться? Ведь нам при первой десериализации, первичной, нужно понять, что это за сообщение, к какому классу оно принадлежит.
так же как и всегда. Сериализуются данные а не логика. Ты же это гоняешь не в рантайме так ? значит конкретные типы есть. В них можно пихнуть это. В какой то класс оно же десериализуется.
Да, есть конкретные типы. И они должны быть помечены неким уникальным маркером, значением известного поля. А таким уникальным маркером обычно является энум, потому что он гарантирует уникальность имён. Ну можно отдельный набор констант завести, только вот зачем - непонятно. А коль скоро у нас имеется маркер, значит нужно выдумывать способ сопоставить маркер с конкретным классом, в том месте, где сообщение будет получено. А это либо большой switch, отсутствие значений в котором может быть проверено компилятором, либо таблица соответствия маркеров и классов. А в таблицу можно забыть добавить значение, и компилятор тут не поможет, в отличие от switch.
Делаешь абстрактный обработчик сообщения, реализуешь для каждого сообщения свою логику, скажем парсить сообщение по особому формату. Это думаю вполне в модель можно положить. Работаешь с абстрактным классом. Зачем тебе маркера Enum мне не понятно. Нужно уменьшать количество изменений в коде, при добавлении логики, а не увеличивать ее.
Вот у нас пришло сообщение. Пока что это строка, в ней json. У нас есть два типа сообщений: А и Б. Как я отличу А от Б в коде? Я полагаю, что для этого у всех сообщений должно быть некое обязательное поле, например MessageType. По его значению и можно будет понять, как десериализовать это сообщение правильно, что там лежит. Я ошибаюсь?
Ты таким же успехом можешь сделать фабрику. Причем почти по той же логике. Ты определяешь классы А и Б, в них определяешь логику валидности данных. Где то в фабрике ты циклом можешь пройтись по скажем константным полям, или методам, если один класс признал формат, выбираешь его, сериализуешь в него. Дополнять список цикла можно через рефлексию наверно, не уверен конечно что так прокатит. НУ или на худой конец ручками. И в итоге. именно класс будет отвечать за наличие проверки валидности сообщения для него. А не внешний свич. Что несколько удобнее. Я почти уверен что можно автоматизировать поиск типов
Можно схему json построить по классу, а потом валидацию входных данных делать, там где без ошибок, тот тип и будет
Если нужна конкретная реализация десереализации для каждого типа, то, теоретически, "вумный как вудка Фаулер" прав. Можно обойтись без энама, а сделать бстрактный хендлер с виртуальным методом десереализации и обработчик для каждого типа. Посмотри паттерн цепочка зависимостей.
В сериализованных данных должен быть некий маркер, однозначно указывающий, что за тип был сериализован. Иначе никак, если не выдумывать заведомо странные способы.
Обсуждают сегодня