
This course includes our updated coding exercises so you can practice your skills as you learn.
See a demo
Описение курса: кто автор, зачем курс, что надо знать, куда занести.
Что за принципы SOLID такие, откуда они взялись и что они нам дают?
Смотрим на Принцип Единственной Обязанности (Single Responsibility Principle, SRP), который утверждает что у конкретного взятого класса должна быть одна конкретная ответственность (и причина меняться). Также связан с Принципом Разделения Ответственности (Separation of Concerns).
Рассказ про Принцип Открыт/Закрыт (Open-Closed Principle, OCP) который требует чтобы классы можно было расширять но не модифицировать. Иначе говоря, расширение функционала должно быть за счет интерфайсов и наследования а подификация уже написанных классов — не хорошо.
Принцип Подстановки Лисков (Liskov Substitution Principle, LSP), названный в честь Барбары Лисков, требует чтобы наследники можно было использовать там, где интерфейсы принимают родителей.
Принцип Разделения Интерфейсов (Interface Segregation Principle, ISP) достаточно прост: не пытайтесь внести в один интерфейс все что вообще можно, потому что тем кто реализует этот интерфейс придется реализовывать много возможно ненужных операций. Вместо этого, просто дробите интерфейсы на более маленькие.
Принцип Инверсии Зависимостей (Dependency Inversion Principle, DIP) никак не связан с внедрениями зависимостей (Dependency Injection, DI/IoC). Этот принцип требует чтобы высокоуровневые модули не полагались на низкоуровневые, чтобы и те и другие вместо этого полагались на абстракции (интерфейсы или абстрактные классы).
Что мы узнали про эти важные принципы SOLID?
Разговариваем про паттерн Строитель и зачем он нужен.
Смотрим на то зачем нам вообще нужен Строитель как таковой.
Реализуем простой Строитель для создания элементов HTML.
Даем нашему строителю fluent-интерфейсы с помощью возврата this из его методов.
Для тех ситуаций когда нужно несколько строителей чтобы достраивать разные части объекта, мы делаем фасад и несколько наследников, сохраняя очень удобный интерфейс.
Реализуем наследование строителей когда они обладают fluent-интерфейсами. Для этого используются рекурсивные дженерики.
Паттерн "Строитель", реализованный в функциональном стиле. Свои плюсы, свои минусы.
Другой подход к использованию строителей, который просто выдает строителя пользователю.
Резюмируем что мы узнали про паттерн Строитель.
Рассказ про фабрики. Почему два паттерна стали одним разделом курса?
Совершенно банальный пример ситуации где рационально использование фабрики.
Простую фабрику реализовать легко, можно просто превратить конструктор в фабричный метод.
Группируем все фабричные методы в отдельный класс. Эй, это разделение ответственности, не?
Внешняя фабрика создала непрятное требование: конструктор объекта должен быть публичным. А что если мы хотим чтобы он был приватным? Решение простое: засовываем фабрику прямо внутрь класса который она создает!
Нам нужно инициализировать класс асинхронно, но конструкторы класса не поддерживают async. Но фабрики нас спасут!
Точно так же как у нас бывают семейства объектов, у нас могут быть соответствующие наборы фабрик. Соответственно появляются и абстрактные фабрики.
Что мы узнали про различные фабрики?
Обсуждение паттерна Прототип (есть также неплохая игра с таким названием).
В .NET есть интерфейс ICloneable, но использование его не рекоммендовано. Почему?
Еще один подозрительный подход, взятый из С++. Не так запутан как ICloneable, но все равно достаточно нечеток. Плюк с этому, его приходится применять рекурсивно, что несколько напрягает.
Как скопировать целый граф объектов без написания какого либо классо-специфичного кода? Все просто, сериализуем и потом десериализуем!
Делаем фабрику для более удобного использования сохраненных прототипов.
Что мы узнали про паттерн Прототип?
Обзор самого ненавистного всеми паттерна. Неужели он настолько опасен?
Не обсуждая всякую ненужную философию связанную с double-checked locking (оно не потокобезопасно!) и реализации с помощью внутренних статических классов (с пустым статическим конструктором чтобы не было beforefieidinit), сразу посмотрим на безопасную, ленивую и потокобезопасную реализацию синглтона.
Ну, синглтон у нас работает, так в чем проблема? В жестких зависимостях что влияет, например, на тот факт что мы не можем подменить синглтон в наших тестах. Oops!
Единственный социально приемлимый способ использования синглтона — внутри DI фреймворка. Обычно маркировка компоненты как синглтон тривиальна.
Вариация на тему синглтона.
Странная вариация паттерна Синглтон, в которой клиент может инстанциировать сколько угодно копий объекта, но все копии шарят между собой один набор (статических) полей. Весьма непрактичная штука.
Ну что, так ли страшен синглтон? Конечно нет, если вы умеете его готовить.
Рассказ про то зачем адаптеры нужны.
Строим адаптер для рисования векторных данных в ситуации когда есть только растровый API.
Адаптер может порождать кучу временных объектов. Чтобы их не плодить каждый раз, их можно и нужно кэшировать!
Свойства которые работают "поверх" существующих данных, преобразовывая структуры данных для внутренних целей.
Смотрим на то как Autofac поддерживает создание адаптеров.
В отличии от С++, в C# нельзя в дженерик засунуть число или строку. Адаптер для литералов (Generic Value Adapter) позволяет нам решить эту проблему. Эта лекция также использует Фабричный Метод и рекурсивные дженерики.
Резюмируем что мы узнали про паттерн Адаптер.
Зачем нужны мосты?
Реализуем паттерн Мост.
Резюмируем что мы узнали про паттерн Мост.
Обзор паттерна Компоновщик.
Давайте реализуем паттерн Компоновщик в применении к простым геометрическим формам и их группированию.
Применяем паттерн Компоновщик к реализации простых нейронных сетей (индивидуальных нейронов и нейронных слоев).
Улучшаем наше демо принципа открыт/закрыт — используем паттерн Компоновщик для создания базового класса для комбинаторов спецификаций.
Что мы узнали про паттерн Компоновщик?
Кто такие декораторы и зачем они нам нужны?
К сожалению класс StringBuilder нельзя наследовать. Посмотрим как же нам тогда сделать фактический наследник этого класса как Декоратор.
Смотрим на то как строить декораторы поверх декораторов.
Можно ли компоновать декораторы как вложенные аргументы дженериков? Можно, но все не так радужно как в С++.
Когда вы реализуете псевдо-множественное наследование, вы по факту реализуете паттерн Декоратор.
Тут мы строим нечто что является и декоратором и адаптером одновременно.
Резюмируем что мы узнали про декораторы.
Обзор курса
Этот курс предоставляет слушателю наиболее полный обзор Паттернов проектирования C# и .NET через чисто практический подход. В частности, на этом курсе вы увидите:
Последние версии языка C# экосистемы .NET
Современные подходы к проектированию: dependency injection, реактивное программирование, и т.п.
Использование современного инструментария разработки (Rider)
Обсуждение вариаций и альтернативных реализаций паттернов
Этот курс покрывает все паттерна Банды Четырех (GoF) а также современные вариации и изменения. Также мы обсудим наличие паттернов встроенных в сам язык или фреймворки .NET (например BCL).
Что еще за Паттерны Проектирования?
Паттерны проектирования — это готовые к использованию решения часто встречающихся задач проектирования. Паттерны были популяризованы в книге 1994 года Design Patterns: Elements of Reusable Object-Oriented Software by Erich Gamma, John Vlissides, Ralph Johnson and Richard Helm (авторов иногда называют Бандой Четырех — Gang of Four — оттуда сокращение GoF).
Оригинальный труд был написан с помощью языков C++ и Smalltalk, но с тех времен утекло много воды, и паттерны успешно адаптировали под все современные языки, такие как C#, Java, PHP, и даже под не-ООП языки, такие как JavaScript.
Применимость паттернов проектирования универсальна: мы встречаем их в библиотеках, некоторые из них встроены прямо в язык, и вы наверняка сами используете их в вашем коде, даже не подозревая что они там есть.
Какие паттерны покрыты в курсе?
В этом курсе вы узнаете про все паттерны Банды Четырех. Вот что вы узнаете из курса:
Принципы проектирования SOLID: Принцип Единственной Обязанности, Принцип Открыт/Закрыт, Принцип Подстановки Лисков, Принцип Разделения Интерфейсов и Принцип Инверсии Зависимостей
Порождающие паттерны: Строитель, Фабрики (Фабричный Метод, Абстрактная Фабрика), Прототип, Синглтон
Структурные паттерны: Адаптер, Мост, Компоновщик, Декоратор, Фасад, Приспособленец, Заместитель
Поведенческие паттерны: Цепочка обязанностей, Команда, Интерпретатор, Итератор, Посредник, Хранитель, Null Object, Наблюдатель, Состояние, Стратегия, Шаблонный Метод, Посетитель
Для кого этот курс?
Этот курс создан для .NET/C# разработчиков которые хотят видеть не только типовые примеры паттернов, но также различные вариации и трюки языка которые можно использовать чтобы писать паттерны в "современном" стиле. Например, с использованием DLR и ImpromptuInterface, мы можем сделать DynamicObject который реализует любой нужный нам интерфейс. Это дает возможность динамического программирования и позволяет делать интересные реализации некоторых паттернов.
В курсе используются достаточно сложные аспекты C#, такие как dynamic, рекурсивные дженерики и т.п.. Также, очень сильно задействованы сторонние библиотеки и фреймворки: Autofac (dependency injection), TPL и async/await для многопоточности, LINQ, Reactive Extensions, и другие.
Стиль преподавания
Весь курс представлен как набор лайв-кодинг сессий, в нем минимум теории и максимум практики! Видео представлены с помощью моей собственной системы Kinetica, которая отбрасывает весь визуальный шум от IDE и позволяет сфокусировать на одном — на коде.
Помимо лекций, в конце каждого раздела есть задача по программированию: нужно реализовать паттерн. Эти задачи помогают закрепить пройденный материал.