Практика «Fractal Painter. DI-container»
При решении данной практики не бойтесь раскрывать подсказки, если возникли какие-либо трудности. В случае успешного выполнения пункта, их так же рекомендуется раскрывать, чтобы сверить ваше решение с образцом.
Продолжайте в том же проекте. Теперь, когда все базовые приготовления сделаны, приступим к внедрению DI-контейнера:
1. Исправляем MainForm
- В классе DIContainerTask переделайте метод GetMainForm так, чтобы объект класса MainForm создавался контейнером
- Произведите биндинг всех классов унаследованных от IUiAction (Искать в ActionsTask.cs и DIContainerTask.cs). А все зависимости для инициализации Action-объектов временно забиндите на обращение к классу Services через метод ToConstant. Все биндинги должны быть в методе
ConfigureContainer
. - Удалите из класса MainForm конструктор без параметров и так же произведите биндинг всех необходимых для инициализации аргументовНа данном этапе программа должна корректно работать. Как вы можете видеть контейнер самостоятельно создает все необходимые зависимости при создании MainForm и уже сейчас становится видно, как программа становится более простой и гибкой. Но не всегда все идет так гладко, как хотелось бы.
Подсказки
2. Исправляем KochFractalAction
- Отрефакторите класс KochFractalAction, также как в первой практике
- Изучите KochFractalAction и поймите, что на самом деле IImageHolder и Pallette ему не нужны. Измените его так, чтобы он принимал только KochPainter.
- После наших действий программа работает некорректно. Подумайте из-за чего это может и попробуйте решить проблему.
- Убедитесь, что всё ещё работает
Подсказки
3. Исправляем DragonFractalAction
- Избавьтесь от использования класса Services в DragonFractalAction
- Убедитесь, что все работает
4. Ребиндим IImageHolder, PictureBoxImageHolder и Palette
- Перебиндите IImageHolder, PictureBoxImageHolder и Palette, так чтобы контейнер их создавал сам не обращаясь к классу Services
- Убедитесь, что дракон рисуется, а палитра изменяет цвет прорисовки кривой Коха
Подсказки
5.1. Улучшаем DragonFractalAction
- Давайте также сделаем более гибким DragonFractalAction и будем принимать все необходимые зависимости через конструктор. Дополнительное ограничение — нельзя менять публичный интерфейс DragonPainter. Особенность в том, что одна из зависимостей DragonPainter — DragonSettings оказывается известной только в процессе работы экшена. Из-за этого вы не можете просить инжектировать в конструктор уже готовый Painter. Вместо этого инжектируйте фабрику DragonPainter-ов. Интерфейс фабрики назовите IDragonPainterFactory, настройте его так чтобы, контейнер сам сгенерировал класс реализующий интерфейс фабрики.
- Если вы все сделали правильно, то IImageHolder теперь нам больше не нужен и от него можно избавиться. Сделайте это.
Подсказки
5.2. Улучшаем DragonFractalAction (Необязательно)
- Для создания DragonPainter-а можно также использовать Func-фабрику. Закомментируйте в конструкторе предыдущую фабрику и инжектируйте Func-фабрику в DragonFractalAction.
(!) Интерфейс фабрики и её биндинг необходимо оставить, т.к. это проверяется в тестах. - Убедитесь, что все работает
Подсказки
6. Улучшаем DragonPainter
- Переведите DragonPainter на использование цветов палитры, как это сделано в KochPainter
- Убедитесь, что экшен настройки палитры работает как надоЕсли вы всё сделали правильно, то для добавления зависимости вам не пришлось править код работы с контейнером вообще. Магия!
Подсказки
7. Избавляемся от зависимостей класса Services
- Избавиться от обращений к классу Services при создании AppSettings и ImageSettings. Используйте ToMethod, чтобы доставать нужные зависимости из контейнера:
ToMethod(context => context.Kernel.Get<TService>() ... )
- Убедитесь, что окно настройки размера изображения работают. Фрактал и кривая Коха должны адаптироваться под изменения изображения и не выходить за рамки в случае маленьких размеров.
Подсказки
8. Избавляемся от класса Services
- Теперь к классу Services не происходит никаких обращений и его можно полностью удалить. Сделайте это.
- Убедитесь, что все работаетПо прохождению данного пункта все тесты должны быть зелеными!
9. Автоматизация биндинга классов (Необязательно)
- В больших проектах таких классов, как унаследованные от IUiActions, может быть сотни и тысячи. Подумайте, как сделать так, чтобы контейнер сам их находил и биндил.
Не забудьте подключить библиотекуNinject.Extensions.Conventions;
- Убедитесь, что все работает
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
using System; using System.Windows.Forms; using System.Drawing; using System.Linq; using FractalPainting.App.Fractals; using FractalPainting.Infrastructure.Common; using FractalPainting.Infrastructure.UiActions; using Ninject.Extensions.Conventions; using Ninject; using Ninject.Extensions.Factory; namespace FractalPainting.App { public static class DIContainerTask { public static MainForm CreateMainForm() { var container = ConfigureContainer(); return container.Get<MainForm>(); } |
Стоимость решения этой задачи всего 100 рублей, купи решения у меня 🙂
Внимание! Решение было обновлено в 2021