|
|
|
Создание программы - ООП модель, MVP30.10.2018, 11:10. Показов 70532. Ответов 99
Пример разработки приложения с нуля под WinForms
Рассматриваются такие аспекты разработки как:
В этом примере НЕ рассматриваются шаблоны типа фабрик, не рассматривается внедрение зависимостей (DI). Используется простой вариант шаблона Model-View-Presenter, адаптированный под специфику WinForms. Этот топик перекликается с этим FAQ, и является практическим примером к нему. Комментарии и вопросы - приветствуются. Постановка задачи Требуется создать приложение - опросник. Опросник будет состоять из нескольких вопросов с различными вариантами ответов. Вопросы могут быть двух видов - с выбором одного ответа из набора возможных, и открытые вопросы, в которых респондент может указать произвольный ответ в виде текста. В опроснике нужно предусмотреть возможность задавать некоторые вопросы и альтернативы только при выполнении некоторых условий, например если в предыдущем вопросе респондент выбрал определенный ответ. Приложение должно состоять из двух частей - конструктора опросника и приложения в котором респондент может ответить на вопросы готового опросника. Результаты опроса должны выгружаться в виде, пригодном для дальнейшей обработки.
18
|
|
| 30.10.2018, 11:10 | |
|
Ответы с готовыми решениями:
99
Встраивание Google RESTful pattern A в модель MVP Создание дочернего окна в MVP
|
|
|
|||||||||||||||||||||
| 30.10.2018, 11:16 [ТС] | |||||||||||||||||||||
|
Шаг 1: Модель
Первое с чего начнем разработку - продумаем модель предметной области (которая также называется доменной моделью, объектной моделью, ООП моделью). Нашей целью является создание классов, которые максимально точно отражают предметы внешнего мира, со всеми присущими им свойствами, зависимостями и функционалом. В данном случае нашей предметной областью является опросник. Внимательно посмотрим на постановку задачи (которое также называется техническим заданием - ТЗ), выпишем существительные, которые там присутствуют. Это такие слова как: опросник, вопросы, варианты ответов, респондент, ответ, текст, альтернативы, условия. Каждое из этих слов является некоторой сущностью предметной области. Все они - кандидаты на отдельный класс. Проанализировав эти сущности, можно сформировать структуру данных, которая определяет как данные связаны между собой:
Кроме того у нас есть еще условия, респонденты и ответы. Эти сущности пока рассматривать не будем. Смотря на структуру, понимаем, что у нас должны быть три класса: Опросник - Questionnaire. Вопрос - Quest. Вариант ответа (альтернатива) - Alternative. Поскольку сущности связаны глаголом "состоит" (опросник состоит из вопросов, вопрос состоит из альтернатив), то это является намеком на связь типа композиция или агрегация. Исходя из структуры данных, можно сформировать уже модель в виде классов. Я буду использовать композицию:
В свою очередь, Quest наследуется от списка Alternative, поскольку он является списком альтернатив. Оба класса являются также композицией: опросник является композицией вопросов, вопрос - композиция альтернатив. Вместо наследования от списка, мы бы могли использовать агрегацию, типа такой:
Далее, в наших классах есть такие поля как Title - текст самого вопроса или альтернативы, и поля Id и Code. Эти поля нужны как идентификаторы вопросов и альтернатив. Идентификаторы позволят в будущем ссылаться на соответствующий вопрос или альтернативу. В отличие от поля Title, идентификаторы не будут меняться и их значение будет уникальным. Простейшая модель предметной области готова. Она не окончательная и будет развиваться в процессе разработки. Шаг 2: Создание проекта, минимального функционала и Unit - теста. Приступим к программированию. Создадим в VisualStuio проект типа Windows Forms Application под .NET Framework 4.5. Создадим папку Core (ядро), и разместим в ней классы нашей модели данных. Поскольку нашу модель нужно будет сохранять на диск и читать с диска, сразу сделаем такую возможность. Для этого будем использовать бинарную сериализацию, разработав универсальный класс SaverLoader:
Разместим этот класс также в папке Core. Теперь протестируем нашу модель - хотелось бы убедиться, что можно создать опросник, вопросы, альтернативы, а также убедиться что опросник сохраняется в файл и читается из него. Это можно было бы сделать через тестовое приложение, но вместо этого, воспользуемся технологией Unit - тестирования. Для этого, создадим в VisualStudio еще один проект типа Unit Test Project. Создадим следующий юнит-тест в классе UnitTest1:
Сейчас наш проект будет выглядеть следующим образом: У меня проект называется WindowsFormsApplication396. Разумеется, у вас он может называться по-другому. В дальнейшем мы переименуем его на более осмысленное название. Запускаем Unit-тест (выпадающее меню на проекте UnitTestProject/Run Unit Test). Убеждаемся, что все работает: Полный код проекта на данном этапе:
12
|
|||||||||||||||||||||
|
|
|||||||||||
| 30.10.2018, 11:42 [ТС] | |||||||||||
|
Шаг 3: Развиваем модель.
На Шаге 1, мы не рассмотрели такую сущность как "ответ". В нашей предметной области есть два объекта высшего уровня - это сам опросник и заполненная анкета, которая состоит из ответов респондента на опросник. Оформим заполненную анкету с ответами как отдельный класс Anketa. На самом деле, такого слова как Anketa в английском языке нет, и правильнее было бы называть заполненную анкету как Form. Но с таким названием мы будем путаться с формами WinForms, поэтому я сделал такое название. В общем случае, это конечно же неправильно. Класс Anketa будет состоять из ответов респондента - Answer.
Так же как и остальные классы модели, пометим классы атрибутом [Serializable], что бы иметь возможность сериализовать анкету. Для новых классов создадим Unit - тест, который также проверит создание анкеты, добавление ответов и чтение/сохранение анкеты в/из файла:
Полный код проекта на этом шаге:
9
|
|||||||||||
|
|
||||||
| 30.10.2018, 12:24 [ТС] | ||||||
|
Шаг 3: Создание пользовательского интерфейса
Мы бы могли и дальше развивать нашу модель, но на этом этапе нужно создать пользовательский интерфейс. И вот почему. Здесь мы будем применять такую методику разработки как непрерывная интеграция. Смысл заключается в том, что бы мы постоянно имели на руках минимальную рабочую версию приложения - Minimal Valuable Product - MVP (не путать с аббревиатурой для Model-View-Presenter, а также с Most Valueable Professional, все они MVP). MVP создается для того, что бы мы всегда могли посмотреть и пощупать наше приложение, показать его будущему пользователю, выявить недостатки модели и интерфейса на ранних этапах разработки. Цикл разработки при непрерывной интеграции выглядит примерно следующим образом: разработка модели -> разработка интерфейса -> тестирование -> рефакторинг -> переход к первому пункту Таким образом, разработка заключается в постоянном внесении небольших изменений в модель и интерфейс, тестировании (возможно с привлечением заказчика, ведь у нас есть рабочая демка), рефакторинге и снова переходе на новый цикл. Зачем это все нужно? Лучше иметь простую и примитивную рабочую программу, чем сложную, навороченную но неработающую. Если в конце разработки окажется, что мы вообще неправильно поняли предметную область, и вообще заказчик имел ввиду совсем другое, то переделка огромной программы будет гораздо дороже, чем переделка маленькой. Наш интерфейс конечно не будет содержать всех возможностей, часть будет представлена заглушками. Но это будет рабочая программа. Итак. В нашем главном проекте переименуем форму в MainForm, кинем на нее тулбар, несколько кнопок и FlowLayoutPanel, которая будет контейнером для нашего конструктора опросника. В главной форме создадим поле Questionnaire questionnaire;, которое будет содержать текущий опросник.Полный код главной формы выглядит так:
Далее, создаем в проекте папку Controls. Создаем UserControl, который назовем QuestPanel. Этот контрол будет ответственен за отображение Quest из модели опросника. Он пока что будет пустым, без кода. Запускаем нашу форму, клацаем на кнопочки, убеждаемся, что все работает. На данном этапе интерфейс программы выглядит так: Полный код проекта:
8
|
||||||
|
14122 / 9341 / 1350
Регистрация: 21.01.2016
Сообщений: 35,099
|
|
| 30.10.2018, 12:55 | |
|
Storm23, ох, не знаю. Не нравится мне, что опросник унаследован от коллекции вопросов. И идентификаторы тут как симуляция реляционной базы. Надо ли здесь такое?
Опросник не является списком вопросов. Он из них состоит, содержит их. Так же, он может и ответы содержать. И ещё что (к примеру, замеренное время прохождения опроса). К тому же, наследование от List<T> даёт возможность любому коду менять состав вопросов этого опросника. Тоже самое с вопросами.И зачем Code и Id? Это же не база данных, тут всё прямыми связями можно разрулить. Это будет сильно проще и явнее.
2
|
|
|
|
|||
| 30.10.2018, 13:09 [ТС] | |||
|
3
|
|||
|
|
|||||||||||
| 30.10.2018, 13:09 [ТС] | |||||||||||
|
Шаг 4: Добавление сервисных классов, дальнейшее развитие интерфейса
Существует два варианта реализации доменной модели: модель Rich и модель Anemic. Основная разница в том, что в Rich объекты доменной модели содержат функционал, а в Anemic - нет. В Anemic логика и функционал выносятся в отдельные сервисные классы. В данном приложении я буду использовать Anemic модель. На самом деле это не имеет каких-либо обоснований. Ну вот просто так мне захотелось. В реальности чаще применяется Rich, она же является более правильной с точки зрения ООП. С другой стороны, Anemic тоже имеет свои преимущества. В данной задаче Anemic мне показалась более подходящей. Итак. Для работы программы, нам нужно обеспечить простейшие действия с опросником: добавление и удаление вопросов, изменение порядка вопросов. Для реализации этих действий разработаем сервисный класс QuestionnaireManipulator:
Далее продолжаем развивать наш интерфейс. Добавим на панель QuestPanel несколько контролов для отображения вопроса: Реализуем в панели следующий код:
Содержит два основных метода: public void Build(...) - вызывается для построения интерфейса. В этот метод передаются объекты доменной модели, которые нужно отобразить. Этот метод - единственный public метод, который может вызываться внешним кодом.private voic UpdateObject() - метод который передает данные обратно - из интерфейса в доменный объект.Также, есть два события: public event Action Changed - вызывается когда вопрос был изменен из интерфейсаpublic event Action QuestionnaireListChanged - вызывается когда был изменен список вопросовКонтрол содержит также пару обработчиков кликов кнопок и текстбоксов. Запускаем наше приложение, убеждаемся что работает добавление/удаление вопросов, перемещение вопросов в списке, редактирование полей вопросов, сохранение и чтение из файла.
6
|
|||||||||||
|
|
|||||||||||
| 30.10.2018, 13:44 [ТС] | |||||||||||
|
Шаг 5: Дальнейшее развитие интерфейса и сервисов
Переходим на следующий цикл разработки. В предыдущем шаге мы разработали сервисный класс для Questionnaire. Теперь сделаем аналогичный класс для Quest:
Также создаем новый UserControl, который назовем AlternativePanel. Этот контрол предназначен для отображения альтернативы вопроса. AlternativePanel выглядит так: Код AlternativePanel следующий:
Иконки для интерфейса можно подобрать здесь и здесь. Иконки в стиле material здесь. Теперь наш интерфейс выглядит следующим образом: Клацаем на кнопочки, убеждаемся, что все работает. Полный код проекта на данный момент:
5
|
|||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| 30.10.2018, 14:59 [ТС] | ||||||||||||||||||||||||||||||||||||
|
Шаг 6: Добавление бизнес-логики, рефакторинг
Бизнес-логика это набор правил по которым функционирует доменная модель. Часто бизнес-логика это собственно то, что делает программа, помимо хранения данных. До этого момента у нас в программе практически не было бизнес-логики. Внимательно посмотрим на модель данных и на поля-идентификаторы Quest.Id и Alternative.Code. Исходя из бизнес-логики предметной области, понятно, что идентификаторы должны быть уникальными. Quest.Id должен быть уникальным в пределах опросника, а Alternative.Code должен быть уникальным в пределах одного вопроса. Однако, наш интерфейс позволяет вбивать произвольные идентификаторы, и возможна ситуация, когда будет несколько вопросов с одинаковыми Id, или несколько альтернатив с одинаковыми кодами. Постараемся этого избежать. Во-первых, сделаем правки в методах добавления вопроса и добавления альтернативы. Пусть эти методы сами генерируют уникальное имя:
Что бы этого избежать, создадим еще один сервис QuestionnaireValidator, который будет проверять корректность всех идентификаторов в опроснике и генерировать исключение, если что-то не в порядке:
Обратим внимание на то, что QuestionnaireValidator генерирует исключение. Это исключение нужно отлавливать и выдавать пользователю сообщение. Однако, таких мест будет много, и мне лень везде писать try/catch. Для того, что бы этого избежать, будем использовать глобальный обработчик исключений, который реализуется в классе ExceptionHandler:
Далее. Посмотрим внимательно на код метода QuestionnaireManipulator.MoveQuest() и код QuestManipulator.MoveAlt(). Видим, что код этих методов практически одинаков, а различия только в типах данных. Поскольку, согласно принципу DRY, код не должен дублироваться, то вынесем этот метод в отдельный метод отдельного класса. Дадим ему имя ListHelper. Сделаем там обобщенный метод, который может передвигать элементы в списке любого типа:
То что мы сделали только что - называется рефакторинг. Рефакторинг не меняет функционала программы, но при рефакторинге меняется код программы, с целью его оптимизации, перегруппировки, очистки от мусора, дублирования кода и т.д. Запускаем программу. Замечаем, что новые вопросы и альтернативы теперь автоматически нумеруются. А если их изменить и создать несколько вопросов или альтернатив с одинаковыми кодами, то программа выдает сообщение об ошибке и файл не сохраняется, до тех пор, пока дублирования не будут исправлены. Текущий вариант программы - в присоединенном файле.
6
|
||||||||||||||||||||||||||||||||||||
|
|
||||||
| 30.10.2018, 15:29 [ТС] | ||||||
|
Шаг 7: Продолжаем рефакторинг
Модель данных и логику лучше выделить в отдельный проект. Это нужно потому, что модель может использоваться в нескольких разных приложениях. Кроме того, вынеся модель в отдельный проект мы гарантированно изолируем ее от интерфейса. Создадим отдельный проект типа Class Library. Назовем его QuestCore. Зададим неймспейс по-умолчанию QuestCoreNS. Обратите внимание, что лучше когда имя неймспейса не совпадает с именем проекта. В противном случае, в будущем, могут возникнуть некоторые проблемы из-за совпадений имен. Перенесем целиком папку Core из основного проекта в новый проект. Кроме того, разделим классы на две папки. В папку Model положим классы модели (Questionnaire, Quest, Alternative и т.д.). А в папку Services положим классы-сервисы (QuestionnaireManipulator, QuestionnaireValidator и т.д.). Кроме того, создадим еще папку Helpers, куда вынесем классы ListHelper и SaverLoader. Папки Services и Helpers отличаются тем, что в Services хранятся классы, которые связаны с доменной моделью, а папка Helpers содержит универсальные классы, которые никак не связаны с моделью. Теперь проект выглядит следующим образом: Далее, на предыдущем шаге мы добавляли некоторый функционал, но не создали юнит-тестов для него. Создаем Unit - тест для QuestionnaireValidator:
Текущий исходник:
4
|
||||||
|
|
||||||||||||||||||||||||||||||||||||
| 30.10.2018, 19:00 [ТС] | ||||||||||||||||||||||||||||||||||||
|
Шаг 8: Создаем модель и интерфейс для интервью
Все что мы разрабатывали в предыдущих шагах было ориентировано на конструктор опросника. Теперь разработаем приложение для ответов на вопросы. Поскольку прохождение интервью - довольно сложный процесс со своей бизнес-логикой, то для него нужно создать свою модель и свои сервисы. Но прежде доработаем модель самого опросника. Вспоминаем, что в техническом задании говорилось о том, что вопросы и альтернативы показываются только при заданных пользователем условиях. Для того, что бы отобразить этот факт, создадим класс Condition, который инкапсулирует в себе проверку условий. Мы пока не знаем внутреннюю реализацию этого класса, поэтому пока сделаем заглушку в методе проверки условий:
Condition.Check(Anketa anketa).Далее, вспоминаем, что в ТЗ говорилось о том, что вопросы бывают разных типов. Отобразим этот факт, создав тип QuestType и создав поле этого типа в классе Quest:
Создадим класс Interview:
Создадим также сервис InterviewManipulator который будет реализовывать бизнес-логику интервью:
Теперь можем приступать к созданию интерфейса для прохождения интервью. Создадим новый проект типа Windows Forms. Назовем его QuestInterview. В главной форме делаем следующий код:
Для отображения конкретного вопроса, разрабатываем отдельный UserControl, который будет отображать вопрос, и позволять пользователю отвечать на него: Вот код этого контрола:
Запускаем приложение, открываем заранее созданную анкету, убеждаемся, что все работает: Полный код проекта на этом шаге:
4
|
||||||||||||||||||||||||||||||||||||
|
|
|||||||||||||||||||||
| 30.10.2018, 21:09 [ТС] | |||||||||||||||||||||
|
Шаг 9: Калькулятор условий, редактор условий
В интерфейсе конструктора была кнопочка запуска интервью Run, которая не имела функционала. Теперь, когда у нас есть интерфейс для прохождения интервью, мы можем сделать запуск тестового интервью прямо из конструктора:
Вопрос и альтернативы теперь содержат ссылку "Если", при нажатии на которую, открывается окно конструктора условий. Само окно конструктора пока пустое. Если условие было сформировано, вместо ссылки будет показан текст самого условия. Также появился комбобокс с выбором типа вопроса. Теперь разработаем редактор условий. Я долго думал, как реализовать условия в этом проекте, так что бы было максимально просто. У меня есть как минимум четыре разных варианта реализации. Но я выбрал тот, который требует минимум кода и в тоже время достаточно универсален - через метод DateTable.Compute(). Этот метод может вычислять логические выражения с поддержкой скобок, связок and/or/not, операторов =, <> и т.д. Для вычисления выражений создадим сервисный класс ConditionCalculator:
Теперь можем написать реализацию интерфейса редактора условий: Код редактора:
Создаем тестовую анкету с условиями: Запускаем анкету на выполнение, убеждаемся что условия работают: Создаем Unit-тест на калькулятор:
Полный код проекта на этом этапе:
4
|
|||||||||||||||||||||
|
|
|||||||||||||||||||||
| 30.10.2018, 23:58 [ТС] | |||||||||||||||||||||
|
Шаг 10: Окончательная доводка приложения
В начальном ТЗ было указано, что должен быть экспорт данных во внешние форматы. Сделаем экспорт заполненных анкет в CSV файл. Для этого создадим сервисный класс Export:
Далее. В процессе разработки валидатора опросника, я упустил из виду тот случай, когда у вопроса не создана ни одна альтернатива. Такого быть не должно, поэтому добавляем такую проверку в валидатор:
bool changed, который будет равен true, если в опроснике есть несохраненные изменения.Будем отлавливать событие Changed у панелей вопросов, и если событие срабатывает, то присваиваем флажку true. При сохранении же файла, флажок changed сбрасывается. Теперь, при выходе из программы или при попытке открыть новый файл, сначала будет проверяться есть ли изменения в текущем опроснике, и если изменения есть - пользователю будет предлагаться сохранить текущий опросник: Кроме того, кнопка "Сохранить" теперь будет активна только тогда, когда в документе есть изменения. Далее. Если вы запускали программу, то наверняка заметили, что при перестройке формы, контролы мигают и сбрасывается скорлл. Это очень неудобно. Для того, что бы этого избежать, создаем специальный хелпер, который будет запоминать позицию скролла, отключать прорисовку контрола на время перестройки, и затем восстанавливать скролл и отрисовку:
Теперь панели не мигает и скролл сохраняет свое положение при перестройке. Сделаем окончательные правки: - Зададим иконки для приложений и для форм. - Переименуем проект в QuestConstructor. Переименуем также неймспейс на QuestConstructorNS. - Удалим лишние неиспользуемые иконки из ресурсов. - Сделаем небольшие изменения в интерфейсе, удалим лишние надписи, уменьшим некоторые иконки. Приложение готово: Полный код проекта:
4
|
|||||||||||||||||||||
|
187 / 100 / 19
Регистрация: 15.09.2011
Сообщений: 801
|
||||||||
| 31.10.2018, 05:41 | ||||||||
|
Здравствуйте.
Я переделал вот так: Кликните здесь для просмотра всего текста
Просто как идею преподнёс. Единственно, потребуется проверка на этапе, когда идёт загрузка из файла - там могут быть косяки просто.
0
|
||||||||
|
|
|||
| 31.10.2018, 09:20 [ТС] | |||
|
Дело в том, что эти идентификаторы используются: 1 ) При написании условий. В условиях пишется выражения типа A1 = 12. Это означает, что текущий вопрос или альтернатива задается только если в вопросе A1 был указан код альтернативы 12. Никто не будет писать условия типа A-12fe56-54784543432-ef898a = 12. Понимаете? Идентификатор здесь играет ту же роль что и имя переменной в программировании. Он должен быть достаточно простым. 2) При экспорте. Обратите внимание на экспорт в CSV. Там экспортируются идентификаторы вопросов в шапке и коды альтернатив в теле таблицы. Разумеется никто не хочет видеть там километровые бессмысленные имена типа GUID. 3) Так же при экспорте в программы обработки статистики. Дело в том, что профессиональные статистические пакеты(SPSS, Statistica) работают только с числами. То есть коды альтернатив должны быть только числа, а идентификаторы вопросов - не более 8 символов (если не изменяет память). 4) При написании отчетов. В отчете вы не будете писать фразы типа "20% респондентов положительно ответили на вопрос A1221121-342434-43243243243". 5) При написании скриптов и SQL запросов. Для вывода стат таблиц в том же SPSS или для вывода статистик из того-же MSSQL- вам нужно указать имена вопросов, по которым выводится статистика. Опять же нужно краткое, простое имя. 6) Ну и удобство пользователя. Пользователю удобно когда номера вопросов идут подряд. Даже если пользователь переместил вопрос по списку, все равно удобно, потому что он видит что номера идут не по порядку и вспоминает, что он делал перемещение. Как ни крути это лучше чем случайные незапоминающиеся коды. И еще несколько моментов. Обычно, те, кто пишет такого рода программы первый раз, завязываются на сам текст вопроса или альтернативы. То есть сама формулировка вопроса и сам текст альтернативы выступают идентификатором. Это неправильно. Во-первых, потому, что формулировки могут повторяться и не быть уникальными. Во-вторых, присутствует та же проблема очень длинных названий и нечисловых кодов. И в-третьих есть проблема обратной совместимости. Если вы вдруг решили поменять формулировку вопроса (например нашли там ошибки, или звучит неоднозначно) - то анкеты, которые были пройдены ДО этого окажутся несовместимыми с новыми анкетами, потому что один и тот же вопрос будет иметь уже другое название. То же касается альтернатив. А вот если использовать идентификаторы, то такой проблемы нет, потому что формулировка вопроса может меняться сколько угодно, а идентификатор то не меняется. ![]() Доменные объекты в Anemic не должны содержать логику.
1
|
|||
|
187 / 100 / 19
Регистрация: 15.09.2011
Сообщений: 801
|
||
| 31.10.2018, 09:50 | ||
|
Если все вопросы идут по порядку, тогда можно просто получить номер последнего вопроса и начинать отсчёт от него. А если вопросы будут удаляться, то тогда будет белиберда и нарушится порядок вопросов. Да, и ещё, я в основном досконально не просматривал, но кажется, что автор имел ввиду ту структуру, что каждый ответ будет основой для новых вопросов, т.е. будет идти как дерево, которое приведёт к конечной точке или конечному состоянию. Прилажуху запустил, а там просто вопросы и варианты в линейной структуре. По сути, ему надо будет переработать логику QuestionManipulator и немного поменять структуру Quest? Например, если выбрал вариант 2, то возможно, перезатереть все предыдущие варианты и отвечать на вопрос, который уже касается именно варианта 2.
0
|
||
|
|
|||
| 31.10.2018, 10:29 [ТС] | |||
|
В более навороченных системах есть автоматическая перенумерация вопросов. При запуске которой все вопросы нумеруются заново, при этом выражения в условиях автоматически заменяют старые имена на новые. Но это усложнение, я его не делал. PS А впрочем, вы можете реализовать через дерево. Только все вместе - с экспортом, со всем функционалом. Интересно посмотреть на эту реализацию. Я свою реализация предложил и аргументировал. Сделайте другую реализацию - я с удовольствием ее посмотрю. А так, это пока просто слова - про дерево и т.п.
1
|
|||
|
187 / 100 / 19
Регистрация: 15.09.2011
Сообщений: 801
|
||
| 03.11.2018, 12:01 | ||
|
Еле нашёл тему. Теперь у меня есть свободное время. Давайте конктретизируем задачу. Надо больше кода? Предлагаю воспользоваться уже имеющимся проектом - я добавлю изменения. Интересно? У меня необычный ход мыслей, но в рамках данной задачи, я могу работать по шаблону
Добавлено через 30 секунд что от меня требуется? Добавлено через 1 минуту надо уточнить ТЗ, но я хотел бы показать силу именно в ООП в том, что над проектом может работать сразу несколько людей - чтобы автор задачи, наконец, понял, что его задача без классов нерешаема Добавлено через 1 минуту Вы бы его на ГИТ забросили для удобства? Добавлено через 38 секунд Добавлено через 1 минуту Storm23, забросите свою версию в СКВ? Добавлено через 1 минуту Наперёд скажу, что буду работать через парадигму TDD - как раз потренируюсь, а то уже подзабывать начал Добавлено через 1 минуту Форум плодит сообщения - модераторы не спите там Добавлено через 54 секунды Storm23, создавайте репозиторий, в личку бросайте доступ, будем работать над проектом
0
|
||
|
|
||
| 03.11.2018, 12:36 [ТС] | ||
Сообщение было отмечено REALIST07 как решение
Решение
umatkot,
Вот репозиторий https://github.com/Storm-23/QuestConstructor
Можно например добавить функционал по автоматическому перенумерованию вопросов. Так, что бы номера вопросов постоянно шли подряд, даже если пользователь их перемешал или удалил.
2
|
||
|
187 / 100 / 19
Регистрация: 15.09.2011
Сообщений: 801
|
|||||||
| 03.11.2018, 18:48 | |||||||
|
Storm23, создавайте репозиторий, в личку бросайте доступ, будем работать над проектом
Добавлено через 2 минуты Storm23, щас глянем)) Добавлено через 3 минуты Мне же надо сделать так, чтобы вопросы шли псевдорекурсивно? Постараюсь использовать класс Expression Добавлено через 14 минут Так. Через ГИТ подключиться я не сумел(видно, руки из жопы). Проект загрузил. Я сам сформирую цель - нам надо сделать так, чтобы каждый ответ на вопрос вёл к новому вопросу. Нумерация вопросов меня пока не волнует Добавлено через 41 секунду потом разберусь с этим Добавлено через 2 минуты Сразу напишу, что для удобства я загружу в проект библиотеку FluentAssertions - она просто лучше поможет мне определить, что мне потребуется проверить? Так? Добавлено через 7 минут Нихрена, молодец, топикстартер с тебя галлон пива. В адрес Шторма. Он там так всё подробно описал... Добавлено через 4 минуты Препод отвалится - гарант, нихрена она там проработал... Добавлено через 46 секунд Storm23, тебе заняться нечем что-ли? Добавлено через 2 минуты это не коммерческий проект - это ПРОТОТИП ты чё там сделал? Добавлено через 1 минуту Люди вы гляньте как надо делать прилажухи Добавлено через 5 минут Брат, снимаю шляпу, ты реально крут)))) Добавлено через 1 час 35 минут Фсё? Кликните здесь для просмотра всего текста
Добавлено через 15 секунд А почему??? Добавлено через 1 минуту ТОпикстартер, ты можешь наблюдать зависимости. Добавлено через 1 минуту Ладно, задачу надо довести до конца Добавлено через 9 минут Да я просто кодом любуюсь. Добавлено через 7 минут ))))) Ты крут, брат, супер) Всё так красиво, я бы был бы не против с тобой работать) Это почти Монна Лиза. Я ещё всё не просмотрел, но я просто в ступоре)))) Ладно про меня Добавлено через 1 минуту Это красивый код - все смотрите и учитесь Добавлено через 4 минуты Думаю, что за день не осилю, но это великолепно, ты оправдал все ожидания, просто супер!!! Пока всё не изучил, но это что-то. Ребята, реал. Добавлено через 1 минуту Не по теме: чувствую себя дауном Добавлено через 6 минут Storm23, Запуск пустого вопросника невозможен - это тупо проверка. Я завтра на свежую голову поработаю над кодом
0
|
|||||||
| 03.11.2018, 18:48 | |
|
Помогаю со студенческими работами здесь
20
Модель ООП Закрепить модель ООП Модель работы светодиода ооп ООП модель системы спама Ооп модель телефонного справочника Искать еще темы с ответами Или воспользуйтесь поиском по форуму: |
|
| Опции темы | |
|
|
Новые блоги и статьи
|
|||
|
http://iceja.net/ сервер решения полиномов
iceja 18.01.2026
Выкатила http:/ / iceja. net/ сервер решения полиномов (находит действительные корни полиномов методом Штурма).
На сайте документация по API, но скажу прямо VPS слабенький и 200 000 полиномов. . .
|
Первый деплой
lagorue 17.01.2026
Не спеша развернул своё 1ое приложение в kubernetes.
А дальше мне интересно создать 1фронтэнд приложения и 2 бэкэнд приложения
развернуть 2 деплоя в кубере получится 2 сервиса и что-бы они. . .
|
Расчёт переходных процессов в цепи постоянного тока
igorrr37 16.01.2026
/ *
Дана цепь постоянного тока с R, L, C, k(ключ), U, E, J. Программа составляет систему уравнений по 1 и 2 законам
Кирхгофа, решает её и находит:
токи, напряжения и их 1 и 2 производные при t = 0;. . .
|
Восстановить юзерскрипты Greasemonkey из бэкапа браузера
damix 15.01.2026
Если восстановить из бэкапа профиль Firefox после переустановки винды, то список юзерскриптов в Greasemonkey будет пустым.
Но восстановить их можно так.
Для этого понадобится консольная утилита. . .
|
|
Изучаю kubernetes
lagorue 14.01.2026
А пригодятся-ли мне знания kubernetes в России?
|
Сукцессия микоризы: основная теория в виде двух уравнений.
anaschu 11.01.2026
https:/ / rutube. ru/ video/ 7a537f578d808e67a3c6fd818a44a5c4/
|
WordPad для Windows 11
Jel 10.01.2026
WordPad для Windows 11
— это приложение, которое восстанавливает классический текстовый редактор WordPad в операционной системе Windows 11. После того как Microsoft исключила WordPad из. . .
|
Classic Notepad for Windows 11
Jel 10.01.2026
Old Classic Notepad for Windows 11
Приложение для Windows 11, позволяющее пользователям вернуть классическую версию текстового редактора «Блокнот» из Windows 10. Программа предоставляет более. . .
|