День триста шестьдесят второй. #DesignPatterns
Паттерны проектирования
10. Паттерн «Одиночка» (Singleton). Окончание
«Синглтон» — это самый критикуемый паттерн, описанный «бандой четырех», главный недостаток которого кроется в его определении: синглтон гарантирует, что у класса есть только один экземпляр, и предоставляет к нему глобальную точку доступа.
Проблема № 1: «Синглтон гарантирует, что у класса есть только один экземпляр…»
На самом деле бизнес-логика очень редко накладывает жесткие ограничения на количество экземпляров класса. Обычно это наши с вами уловки и попытки оправдать ошибки дизайна: легче связать несколько кусков системы с помощью синглтонов, вместо того чтобы изменить дизайн и передать классам лишь нужные зависимости.
Проблема № 2: «… и предоставляет глобальную точку доступа»
Главная проблема паттерна «Синглтон» заключается в том, что он является глобальной переменной со всеми её недостатками.
- Необходимость конструктора по умолчанию (для ленивой реализации). Это значит, что синглтону нельзя передать требуемые зависимости и он будет использовать другие глобальные объекты. В результате легко прийти к дизайну приложения, состоящего из набора глобальных объектов.
- Неявные зависимости. Если класс имеет много открытых полей или его конструктор принимает слишком большое число аргументов, то он считается сложным, и с его дизайном что-то не так. Но что, если класс не содержит полей и не принимает никаких зависимостей через конструктор, но использует несколько синглтонов? Тогда, чтобы понять его сложность, придется проанализировать все закрытые методы.
- Изменяемое состояние. Это является источником очень коварных ошибок. Внесение изменений в одну часть системы может изменить работу произвольного числа модулей, у которых были определенные предположения относительно состояния синглтона. Синглтон может обладать невидимым состоянием, например кэшированием, но полноценной изменяемости нужно избегать всеми силами.
Возможное применение
1. Синглтон без видимого состояния. Используется, чтобы получить доступ к стабильной справочной информации или некоторым утилитам.
2. Настраиваемый контекст. Синглтон возвращает абстрактный класс или интерфейс, который можно установить при старте приложения или при инициализации юнит-теста.
Советы по использованию
1. Минимальная область использования. Ограничьте использование синглтона минимальным числом классов/модулей. Чем меньше у него прямых пользователей, тем легче будет от него избавиться и перейти на более продуманную модель управления зависимостями. Чем больше у класса пользователей, тем сложнее его изменить. Если вы вынуждены использовать синглтон, то пусть лишь несколько высокоуровневых классов-медиаторов используют его напрямую и передают его экземпляр в качестве зависимостей классам более низкого уровня.
2. Сделайте использование синглтона явным. Если передать зависимость через аргументы конструктора не удается, то сделайте использование синглтона явным. Вместо обращения к синглтону из нескольких методов сделайте статическую переменную и проинициализируйте её экземпляром синглтона.
3. Синглтон или статический класс. Альтернативой паттерну «Синглтон» является использование класса с исключительно статическими членами. Синглтон явно обладает большей гибкостью, но статическими функциями проще пользоваться. Можно предложить следующее правило: при отсутствии состояния и небольшом числе операций используйте статические методы. Если же глобальный объект обладает состоянием, то синглтон будет проще.
Источник: Тепляков С. "Паттерны проектирования на платформе .NET." — СПб.: Питер, 2015. Глава 8.
Паттерны проектирования
10. Паттерн «Одиночка» (Singleton). Окончание
«Синглтон» — это самый критикуемый паттерн, описанный «бандой четырех», главный недостаток которого кроется в его определении: синглтон гарантирует, что у класса есть только один экземпляр, и предоставляет к нему глобальную точку доступа.
Проблема № 1: «Синглтон гарантирует, что у класса есть только один экземпляр…»
На самом деле бизнес-логика очень редко накладывает жесткие ограничения на количество экземпляров класса. Обычно это наши с вами уловки и попытки оправдать ошибки дизайна: легче связать несколько кусков системы с помощью синглтонов, вместо того чтобы изменить дизайн и передать классам лишь нужные зависимости.
Проблема № 2: «… и предоставляет глобальную точку доступа»
Главная проблема паттерна «Синглтон» заключается в том, что он является глобальной переменной со всеми её недостатками.
- Необходимость конструктора по умолчанию (для ленивой реализации). Это значит, что синглтону нельзя передать требуемые зависимости и он будет использовать другие глобальные объекты. В результате легко прийти к дизайну приложения, состоящего из набора глобальных объектов.
- Неявные зависимости. Если класс имеет много открытых полей или его конструктор принимает слишком большое число аргументов, то он считается сложным, и с его дизайном что-то не так. Но что, если класс не содержит полей и не принимает никаких зависимостей через конструктор, но использует несколько синглтонов? Тогда, чтобы понять его сложность, придется проанализировать все закрытые методы.
- Изменяемое состояние. Это является источником очень коварных ошибок. Внесение изменений в одну часть системы может изменить работу произвольного числа модулей, у которых были определенные предположения относительно состояния синглтона. Синглтон может обладать невидимым состоянием, например кэшированием, но полноценной изменяемости нужно избегать всеми силами.
Возможное применение
1. Синглтон без видимого состояния. Используется, чтобы получить доступ к стабильной справочной информации или некоторым утилитам.
2. Настраиваемый контекст. Синглтон возвращает абстрактный класс или интерфейс, который можно установить при старте приложения или при инициализации юнит-теста.
Советы по использованию
1. Минимальная область использования. Ограничьте использование синглтона минимальным числом классов/модулей. Чем меньше у него прямых пользователей, тем легче будет от него избавиться и перейти на более продуманную модель управления зависимостями. Чем больше у класса пользователей, тем сложнее его изменить. Если вы вынуждены использовать синглтон, то пусть лишь несколько высокоуровневых классов-медиаторов используют его напрямую и передают его экземпляр в качестве зависимостей классам более низкого уровня.
2. Сделайте использование синглтона явным. Если передать зависимость через аргументы конструктора не удается, то сделайте использование синглтона явным. Вместо обращения к синглтону из нескольких методов сделайте статическую переменную и проинициализируйте её экземпляром синглтона.
3. Синглтон или статический класс. Альтернативой паттерну «Синглтон» является использование класса с исключительно статическими членами. Синглтон явно обладает большей гибкостью, но статическими функциями проще пользоваться. Можно предложить следующее правило: при отсутствии состояния и небольшом числе операций используйте статические методы. Если же глобальный объект обладает состоянием, то синглтон будет проще.
Источник: Тепляков С. "Паттерны проектирования на платформе .NET." — СПб.: Питер, 2015. Глава 8.
День триста шестьдесят третий. #Оффтоп #97Вещей
97 Вещей, Которые Должен Знать Каждый Программист
21. Разделяйте Исключения Бизнес-логики от Технических
По сути, есть всего две причины, из-за которых что-то может пойти не так во время выполнения программы. Это технические проблемы, мешающие работе приложения, и бизнес-логика, не дающая нам использовать приложение неправильно. Большинство современных языков, таких как LISP, Java, Smalltalk и C#, используются исключения для сообщения о возникновении обеих ситуаций. Тем не менее, эти ситуации настолько различны, что относиться к ним следует по-разному. Использование для них одной иерархии исключений, не говоря уже об одних и тех же классах исключений, - это потенциальный источник путаницы.
При возникновении программной ошибки может возникнуть неразрешимая техническая проблема. Например, попытка получить доступ к элементу 83 из массива размера 17, не позволяет программе продолжить выполняться корректно и должна приводить к какому-то исключению. Чуть менее очевидный пример: вызов некоторой библиотечной функции с неподходящими аргументами, приводящий к вышеописанной ситуации внутри библиотеки.
Было бы ошибкой пытаться как-то разрешить те ситуации, которые вы сами вызвали. Вместо этого мы позволяем исключению всплыть на верхний уровень архитектуры и позволяем общему механизму обработки исключений сделать всё возможное, чтобы гарантировать, что система находится в безопасном состоянии: откатить транзакцию, сделать запись в журнале, а также создать дружелюбное сообщение для пользователя.
Вариант этой ситуации, когда вы разрабатываете библиотеку и вызывающая сторона нарушила контракт вашего метода, например, передала недопустимый аргумент или неправильно настроила зависимый объект. Это сравнимо с доступом к 83-му элементу из 17: вызывающий код должен отвечать за проверку, и отсутствие проверки - это ошибка программиста пользователя библиотеки. Правильная реакция на это - выбросить техническое исключение.
Другая, но всё же техническая, ситуация: программа не может продолжить работу из-за проблемы в среде выполнения, такой как не отвечающая база данных. В этой ситуации вы должны предположить, что инфраструктура сделала все возможное, чтобы решить проблему (например, повторила попытку восстановить соединение разумное количество раз) и потерпела неудачу. Даже если причина в другом, ситуация для вызывающего кода аналогична: мало что можно с этим поделать. В этом случае мы сообщаем об этом через исключение, которому позволяем всплыть до уровня общего механизма обработки исключений.
В противоположность этому ситуация, когда программа не может продолжить выполнение по причине ограничений домена. Такая ситуация является исключением, то есть необычна и нежелательна, но не является следствием программной ошибки. Например, попытка снять деньги со счёта с недостаточным количеством средств. Другими словами, такого рода ситуация является частью контракта приложения, и выброс исключения - это просто альтернативный путь обработки ситуации, являющейся частью предметной модели, о котором клиент должен знать и быть готовым к нему. Для этих ситуаций целесообразно создать отдельный вид исключения или отдельную иерархию исключений, чтобы клиент мог обрабатывать ситуацию особым образом.
Смешивание технических и бизнес-исключений в одной и той же иерархии стирает различие и сбивает вызывающего с толку в отношении того, что такое контракт метода, какие условия необходимо обеспечить перед вызовом и какие ситуации должны обрабатываться. Разделение этих случаев вносит ясность и увеличивает вероятность того, что технические исключения будут обрабатываться некоторой прикладной средой, в то время как исключения бизнес-сферы фактически рассматриваются и обрабатываются клиентским кодом.
Источник: https://www.oreilly.com/library/view/97-things-every/9780596809515/
Автор оригинала – Dan Bergh Johnson
97 Вещей, Которые Должен Знать Каждый Программист
21. Разделяйте Исключения Бизнес-логики от Технических
По сути, есть всего две причины, из-за которых что-то может пойти не так во время выполнения программы. Это технические проблемы, мешающие работе приложения, и бизнес-логика, не дающая нам использовать приложение неправильно. Большинство современных языков, таких как LISP, Java, Smalltalk и C#, используются исключения для сообщения о возникновении обеих ситуаций. Тем не менее, эти ситуации настолько различны, что относиться к ним следует по-разному. Использование для них одной иерархии исключений, не говоря уже об одних и тех же классах исключений, - это потенциальный источник путаницы.
При возникновении программной ошибки может возникнуть неразрешимая техническая проблема. Например, попытка получить доступ к элементу 83 из массива размера 17, не позволяет программе продолжить выполняться корректно и должна приводить к какому-то исключению. Чуть менее очевидный пример: вызов некоторой библиотечной функции с неподходящими аргументами, приводящий к вышеописанной ситуации внутри библиотеки.
Было бы ошибкой пытаться как-то разрешить те ситуации, которые вы сами вызвали. Вместо этого мы позволяем исключению всплыть на верхний уровень архитектуры и позволяем общему механизму обработки исключений сделать всё возможное, чтобы гарантировать, что система находится в безопасном состоянии: откатить транзакцию, сделать запись в журнале, а также создать дружелюбное сообщение для пользователя.
Вариант этой ситуации, когда вы разрабатываете библиотеку и вызывающая сторона нарушила контракт вашего метода, например, передала недопустимый аргумент или неправильно настроила зависимый объект. Это сравнимо с доступом к 83-му элементу из 17: вызывающий код должен отвечать за проверку, и отсутствие проверки - это ошибка программиста пользователя библиотеки. Правильная реакция на это - выбросить техническое исключение.
Другая, но всё же техническая, ситуация: программа не может продолжить работу из-за проблемы в среде выполнения, такой как не отвечающая база данных. В этой ситуации вы должны предположить, что инфраструктура сделала все возможное, чтобы решить проблему (например, повторила попытку восстановить соединение разумное количество раз) и потерпела неудачу. Даже если причина в другом, ситуация для вызывающего кода аналогична: мало что можно с этим поделать. В этом случае мы сообщаем об этом через исключение, которому позволяем всплыть до уровня общего механизма обработки исключений.
В противоположность этому ситуация, когда программа не может продолжить выполнение по причине ограничений домена. Такая ситуация является исключением, то есть необычна и нежелательна, но не является следствием программной ошибки. Например, попытка снять деньги со счёта с недостаточным количеством средств. Другими словами, такого рода ситуация является частью контракта приложения, и выброс исключения - это просто альтернативный путь обработки ситуации, являющейся частью предметной модели, о котором клиент должен знать и быть готовым к нему. Для этих ситуаций целесообразно создать отдельный вид исключения или отдельную иерархию исключений, чтобы клиент мог обрабатывать ситуацию особым образом.
Смешивание технических и бизнес-исключений в одной и той же иерархии стирает различие и сбивает вызывающего с толку в отношении того, что такое контракт метода, какие условия необходимо обеспечить перед вызовом и какие ситуации должны обрабатываться. Разделение этих случаев вносит ясность и увеличивает вероятность того, что технические исключения будут обрабатываться некоторой прикладной средой, в то время как исключения бизнес-сферы фактически рассматриваются и обрабатываются клиентским кодом.
Источник: https://www.oreilly.com/library/view/97-things-every/9780596809515/
Автор оригинала – Dan Bergh Johnson
День триста шестьдесят четвёртый. #юмор
В опенспейсах лично мне не доводилось работать. Зато дома при наличии детей - это да, очень похоже.
В опенспейсах лично мне не доводилось работать. Зато дома при наличии детей - это да, очень похоже.
День триста шестьдесят пятый. #NetInternals
2. Как проглотить ThreadAbortException?
Иногда в коде нужно остановить выполнение одного из потоков. Для этого можно использовать метод
Вы можете легко поймать его с помощью блока исключений, но, если вы не сбросите его, оно будет автоматически проброшено выше по стеку.
Еще одна особенность
Также вызов метода
В .NET Core метод
Источники:
- Adam Furmanek «.NET Internals Cookbook» - https://blog.adamfurmanek.pl/
- Евгений Пешков «Особые исключения в .NET» - https://youtu.be/WLSrYgMWif4
2. Как проглотить ThreadAbortException?
Иногда в коде нужно остановить выполнение одного из потоков. Для этого можно использовать метод
thread.Abort(). При вызове метода Abort в останавливаемом потоке выбрасывается исключение ThreadAbortException.Вы можете легко поймать его с помощью блока исключений, но, если вы не сбросите его, оно будет автоматически проброшено выше по стеку.
var thread = new Thread(() => {
try { … }
catch (ThreadAbortException e) {
…
}
});
…
thread.Abort();
Если всё-таки нужно обработать ThreadAbort и выполнить еще какие-то действия в останавливаемом потоке, то можно использовать метод Thread.ResetAbort(). Он прекращает процесс остановки потока и исключение перестаёт прокидываться выше по стеку. Важно понимать, что метод thread.Abort() сам по себе ничего не гарантирует — код в останавливаемом потоке может препятствовать остановке.Еще одна особенность
thread.Abort() заключается в том, что он не сможет прервать код в том случае, если он находится в блоках catch и finally. Внутри кода фреймворка часто можно встретить методы, у которых блок try пустой, а вся логика находится внутри finally. Это делается как раз с той целью, чтобы этот код не мог быть прерван через ThreadAbortException.Также вызов метода
thread.Abort() дожидается выброса ThreadAbortException. Объединим эти два факта и получим, что метод thread.Abort() может заблокировать вызывающий поток:var thread = new Thread(() =>В реальности с этим можно столкнуться при использовании конструкции
{
try { }
catch {
//ThreadAbortException не выбрасывается в catch
}
finally {
//ThreadAbortException не выбрасывается в finally
Thread.Sleep(-1);
}
});
thread.Start();
…
thread.Abort(); //Никогда не вернётся
using. Она разворачивается в try/finally, внутри finally вызывается метод Dispose. Он может быть сколь угодно сложным, содержать вызовы и обработчики событий, использовать блокировки. И если thread.Abort был вызван во время выполнения Dispose, то thread.Abort будет его ждать. Так мы получаем блокировку почти на пустом месте.В .NET Core метод
thread.Abort() выбрасывает PlatformNotSupportedException. И это очень хорошо, потому что мотивирует пользоваться не thread.Abort(), а неинвазивными методами остановки выполнения кода, например с помощью CancellationToken.Источники:
- Adam Furmanek «.NET Internals Cookbook» - https://blog.adamfurmanek.pl/
- Евгений Пешков «Особые исключения в .NET» - https://youtu.be/WLSrYgMWif4
День триста шестьдесят шестой. #Оффтоп #97Вещей
97 Вещей, Которые Должен Знать Каждый Программист
22. Занимайтесь Осознанной Практикой
Осознанная практика – это не просто выполнение работы. Если вы спросите себя «Почему я решаю эту задачу?» и ответом будет «Чтобы её решить», то вы не занимаетесь осознанной практикой.
Вы практикуетесь, чтобы улучшить ваш навык решать задачи. Речь идет о мастерстве и технике. Осознанная практика означает повторение. То есть выполнение задания с целью оттачивания мастерства в том или ином аспекте задания. Повторение уже повторенного. Методично, снова и снова, пока вы не достигнете желаемого уровня мастерства. Вы практикуетесь, чтобы отточить мастерство решения задачи, а не просто решить задачу.
Основная цель оплачиваемой разработки - завершить продукт, в то время как основная цель осознанной практики - повысить производительность. Это не одно и то же. Спросите себя, сколько времени вы тратите на разработку чужого продукта? А сколько на саморазвитие?
Сколько практики требуется, чтобы достичь мастерства? Peter Norvig пишет, что «около 10 000 часов… это магическое число». Mary Poppendieck в «Leading Lean Software Development» заметила, что «Хорошему исполнителю потребуется минимум 10 тысяч часов практики, чтобы стать экспертом».
Навык приходит постепенно, не сразу за 10 000 часов! Тем не менее, 10 000 часов это много: около 20 часов в неделю в течение 10 лет. Увидев эти цифры, можно подумать, что достичь уровня эксперта просто невозможно. Это не так. Уровень во многом зависит от осознанного выбора. Выбор за вами. Исследования последних двух десятилетий показали, что основным фактором приобретения опыта является время, затрачиваемое на осознанную практику. Врожденный талант не является основным фактором. По словам Mary Poppendieck: «Практически все исследователи уровня мастерства сходятся в том, что врожденный талант лишь начало. Необходимо иметь самый базовый уровень, чтобы начать. После чего успеха достигают те, кто больше других работает над этим.»
Нет смысла намеренно практиковать то, в чём вы уже являетесь экспертом. Осознанная практика означает практиковать то, в чем вы не очень хороши.
Peter Norvig: «Ключевой фактор в развитии навыка – практика. Не просто делать что-то снова и снова, но ставить себе задачи чуть выше вашего уровня, пытаться их решать, анализируя свою эффективность и исправляя ошибки.»
Mary Poppendieck: «Осознанная практика не значит делать то, в чем вы сильны, это значит бросать себе вызов, делая то, в чем вы слабы. Это не обязательно удовольствие.»
Осознанная практика - это обучение. Обучение, которое меняет вас, обучение, которое меняет ваше поведение. Удачи.
Источник: https://www.oreilly.com/library/view/97-things-every/9780596809515/
Автор оригинала – Jon Jagger
97 Вещей, Которые Должен Знать Каждый Программист
22. Занимайтесь Осознанной Практикой
Осознанная практика – это не просто выполнение работы. Если вы спросите себя «Почему я решаю эту задачу?» и ответом будет «Чтобы её решить», то вы не занимаетесь осознанной практикой.
Вы практикуетесь, чтобы улучшить ваш навык решать задачи. Речь идет о мастерстве и технике. Осознанная практика означает повторение. То есть выполнение задания с целью оттачивания мастерства в том или ином аспекте задания. Повторение уже повторенного. Методично, снова и снова, пока вы не достигнете желаемого уровня мастерства. Вы практикуетесь, чтобы отточить мастерство решения задачи, а не просто решить задачу.
Основная цель оплачиваемой разработки - завершить продукт, в то время как основная цель осознанной практики - повысить производительность. Это не одно и то же. Спросите себя, сколько времени вы тратите на разработку чужого продукта? А сколько на саморазвитие?
Сколько практики требуется, чтобы достичь мастерства? Peter Norvig пишет, что «около 10 000 часов… это магическое число». Mary Poppendieck в «Leading Lean Software Development» заметила, что «Хорошему исполнителю потребуется минимум 10 тысяч часов практики, чтобы стать экспертом».
Навык приходит постепенно, не сразу за 10 000 часов! Тем не менее, 10 000 часов это много: около 20 часов в неделю в течение 10 лет. Увидев эти цифры, можно подумать, что достичь уровня эксперта просто невозможно. Это не так. Уровень во многом зависит от осознанного выбора. Выбор за вами. Исследования последних двух десятилетий показали, что основным фактором приобретения опыта является время, затрачиваемое на осознанную практику. Врожденный талант не является основным фактором. По словам Mary Poppendieck: «Практически все исследователи уровня мастерства сходятся в том, что врожденный талант лишь начало. Необходимо иметь самый базовый уровень, чтобы начать. После чего успеха достигают те, кто больше других работает над этим.»
Нет смысла намеренно практиковать то, в чём вы уже являетесь экспертом. Осознанная практика означает практиковать то, в чем вы не очень хороши.
Peter Norvig: «Ключевой фактор в развитии навыка – практика. Не просто делать что-то снова и снова, но ставить себе задачи чуть выше вашего уровня, пытаться их решать, анализируя свою эффективность и исправляя ошибки.»
Mary Poppendieck: «Осознанная практика не значит делать то, в чем вы сильны, это значит бросать себе вызов, делая то, в чем вы слабы. Это не обязательно удовольствие.»
Осознанная практика - это обучение. Обучение, которое меняет вас, обучение, которое меняет ваше поведение. Удачи.
Источник: https://www.oreilly.com/library/view/97-things-every/9780596809515/
Автор оригинала – Jon Jagger
День триста шестьдесят седьмой. #ЗаметкиНаПолях
ASP.NET MVC 5.
HTML Формы
Этот материал может показаться довольно примитивным и не относящимся напрямую к ASP.NET MVC, но, как это ни удивительно, такой простой на первый взгляд элемент HTML, как
Атрибуты Action и Method
Форма - это контейнер для элементов ввода: кнопок, флажков, текстовых полей и многого другого. Элементы ввода в форме позволяют пользователю вводить информацию на страницу и отправлять её на сервер. Но как и на какой сервер? Ответы на эти вопросы находятся в двух наиболее важных атрибутах тега
Атрибут
Когда пользователь отправляет форму с помощью HTTP-запроса GET, браузер берёт имена и значения элементов формы и помещает их в строку запроса. Предыдущая форма отправит браузер по следующему URL-адресу (при условии, что пользователь ввёл «dotnet»):
Вы также можете присвоить атрибуту
Ещё важнее то, что глагол GET семантически правильнее использовать, потому что GET представляет собой идемпотентную операцию только для чтения. То есть вы можете отправлять GET-запрос на сервер сколько угодно раз без каких-либо побочных эффектов, потому что GET не изменяет (по крайней мере, не должен) состояние сервера.
С другой стороны, POST - это тип запроса, который используется для отправки транзакции по кредитной карте, добавления товара в корзину или изменения пароля. Запрос POST обычно изменяет состояние сервера, и повторение запроса может привести к нежелательным последствиям. Многие браузеры помогают пользователю избежать повторения запроса POST, показывая предупреждающее сообщение. Веб-приложения обычно используют GET-запросы для чтения данных и POST-запросы для записи (обновления, создания или удаления) данных.
Удивительно, но мне буквально недавно пришлось объяснять это старшему коллеге, который решил изменить GET-запрос поиска в старой версии сайта на POST-запрос в новой версии по причине большого (относительно) объёма данных формы и длинного URL запроса.
Источник: Jon Galloway “Professional ASP.NET MVC 5”. – John Wiley & Sons Inc., 2014. Глава 5.
ASP.NET MVC 5.
HTML Формы
Этот материал может показаться довольно примитивным и не относящимся напрямую к ASP.NET MVC, но, как это ни удивительно, такой простой на первый взгляд элемент HTML, как
form, часто используется неверно даже опытными разработчиками.Атрибуты Action и Method
Форма - это контейнер для элементов ввода: кнопок, флажков, текстовых полей и многого другого. Элементы ввода в форме позволяют пользователю вводить информацию на страницу и отправлять её на сервер. Но как и на какой сервер? Ответы на эти вопросы находятся в двух наиболее важных атрибутах тега
form: action и method.Атрибут
action сообщает браузеру, куда отправлять информацию, поэтому содержит URL-адрес. Он может быть относительным, или абсолютным, если вы хотите отправить информацию в другое приложение или на другой сервер. Следующая форма отправляет поисковый запрос (текстовое поле с именем q) на страницу поиска Google из любого приложения:<form action="https://www.google.com/search">Тег формы в предыдущем фрагменте кода не включает атрибут
<input name="q" type="text" />
<input type="submit" value="Search!" />
</form>
method. Атрибут method сообщает браузеру, какой HTTP метод (POST или GET) использовать при отправке информации. Хотя может показаться, что для отправки информации на сервер значением по умолчанию должно быть post, на самом деле значением по умолчанию является get. То первая строчка кода выше эквивалентна следующей:<form action="https://www.google.com/search" method="get">
Когда пользователь отправляет форму с помощью HTTP-запроса GET, браузер берёт имена и значения элементов формы и помещает их в строку запроса. Предыдущая форма отправит браузер по следующему URL-адресу (при условии, что пользователь ввёл «dotnet»):
https://www.google.com/search?q=dotnet
GET или POST?Вы также можете присвоить атрибуту
method значение post, и в этом случае браузер помещает данные формы в тело HTTP-запроса. И хотя можно успешно отправить POST-запрос в поисковую систему и получить результаты, GET-запрос предпочтительнее. В отличие от POST, вы можете сохранить запрос GET в закладках, потому что все параметры находятся в URL. Вы можете использовать URL-адрес в качестве гиперссылки в электронной почте или на веб-странице и сохранять при этом все значения формы.Ещё важнее то, что глагол GET семантически правильнее использовать, потому что GET представляет собой идемпотентную операцию только для чтения. То есть вы можете отправлять GET-запрос на сервер сколько угодно раз без каких-либо побочных эффектов, потому что GET не изменяет (по крайней мере, не должен) состояние сервера.
С другой стороны, POST - это тип запроса, который используется для отправки транзакции по кредитной карте, добавления товара в корзину или изменения пароля. Запрос POST обычно изменяет состояние сервера, и повторение запроса может привести к нежелательным последствиям. Многие браузеры помогают пользователю избежать повторения запроса POST, показывая предупреждающее сообщение. Веб-приложения обычно используют GET-запросы для чтения данных и POST-запросы для записи (обновления, создания или удаления) данных.
Удивительно, но мне буквально недавно пришлось объяснять это старшему коллеге, который решил изменить GET-запрос поиска в старой версии сайта на POST-запрос в новой версии по причине большого (относительно) объёма данных формы и длинного URL запроса.
Источник: Jon Galloway “Professional ASP.NET MVC 5”. – John Wiley & Sons Inc., 2014. Глава 5.
День триста шестьдесят восьмой. #DesignPatterns
Паттерны проектирования
11. Паттерн «Абстрактная фабрика» (Abstract Factory)
Фабрика — это второй по популярности паттерн после паттерна «Синглтон». Существуют две классические разновидности фабрик: «Абстрактная фабрика» и «Фабричный метод», предназначенные для инкапсуляции создания объекта или семейства объектов. На практике очень часто отходят от классических реализаций этих паттернов и называют фабрикой любой класс, инкапсулирующий в себе создание объектов.
Назначение: абстрактная фабрика предоставляет интерфейс для создания семейства взаимосвязанных или родственных объектов.
Причины использования:
Когда бизнес-логика программы должна работать с разными видами связанных друг с другом продуктов, не завися от конкретных классов продуктов. Абстрактная фабрика скрывает от клиентского кода подробности того, как и какие конкретно объекты будут созданы. Но при этом клиентский код может работать со всеми типами создаваемых продуктов, поскольку их общий интерфейс был заранее определён.
Классическая диаграмма приведена на рисунке ниже:
-
-
-
-
Основная особенность абстрактной фабрики заключается в том, что она предназначена для создания семейства объектов, что сильно сужает ее применимость. Но в некоторых предметных областях или инфраструктурном коде периодически возникают задачи, которые решаются набором классов: сериализаторы/десериализаторы, классы для сжатия/распаковки, шифрования/дешифрования и т. п.
Приложение должно использовать согласованные типы объектов, и абстрактная фабрика идеально подходит для решения этой задачи. Интерфейс абстрактной фабрики объявляет набор фабричных методов, а конкретная реализация обеспечивает создание этого семейства объектов.
Одной из разновидностей реализации паттерна «Абстрактная фабрика» является обобщённая фабрика, которая позволяет создавать произвольные типы объектов:
Применимость паттерна
Абстрактная фабрика представляет собой слой для полиморфного создания семейства объектов. Её использование подразумевает обязательное наличие двух составляющих: 1) семейства объектов и 2) возможности замены создаваемого семейства объектов во время исполнения.
Иногда необходимость полноценной абстрактной фабрики очевидна с самого начала, но обычно лучше начать с наиболее простого решения и добавить гибкость лишь в случае необходимости.
Источник: Тепляков С. "Паттерны проектирования на платформе .NET." — СПб.: Питер, 2015. Глава 9.
Паттерны проектирования
11. Паттерн «Абстрактная фабрика» (Abstract Factory)
Фабрика — это второй по популярности паттерн после паттерна «Синглтон». Существуют две классические разновидности фабрик: «Абстрактная фабрика» и «Фабричный метод», предназначенные для инкапсуляции создания объекта или семейства объектов. На практике очень часто отходят от классических реализаций этих паттернов и называют фабрикой любой класс, инкапсулирующий в себе создание объектов.
Назначение: абстрактная фабрика предоставляет интерфейс для создания семейства взаимосвязанных или родственных объектов.
Причины использования:
Когда бизнес-логика программы должна работать с разными видами связанных друг с другом продуктов, не завися от конкретных классов продуктов. Абстрактная фабрика скрывает от клиентского кода подробности того, как и какие конкретно объекты будут созданы. Но при этом клиентский код может работать со всеми типами создаваемых продуктов, поскольку их общий интерфейс был заранее определён.
Классическая диаграмма приведена на рисунке ниже:
-
AbstractFactory — объявляет интерфейс (с возможной базовой реализацией) для создания семейства продуктов;-
AbstractProductA, AbstractProductB — семейство продуктов, которые будут использоваться клиентом для выполнения своих задач;-
ProductA1, ProductB1 — конкретные типы продуктов;-
Client — клиент фабрики, который получает конкретные продукты для реализации своего поведения.Основная особенность абстрактной фабрики заключается в том, что она предназначена для создания семейства объектов, что сильно сужает ее применимость. Но в некоторых предметных областях или инфраструктурном коде периодически возникают задачи, которые решаются набором классов: сериализаторы/десериализаторы, классы для сжатия/распаковки, шифрования/дешифрования и т. п.
Приложение должно использовать согласованные типы объектов, и абстрактная фабрика идеально подходит для решения этой задачи. Интерфейс абстрактной фабрики объявляет набор фабричных методов, а конкретная реализация обеспечивает создание этого семейства объектов.
Одной из разновидностей реализации паттерна «Абстрактная фабрика» является обобщённая фабрика, которая позволяет создавать произвольные типы объектов:
class GenericAbstractFactory {
public object Make(string id) { ... }
public IProduct MakeProduct(string id) { ... }
public T MakeGeneric<T>(string id) where T : IProduct { ... }
}
…
var factory = new GenericAbstractFactory();
var o = factory.Make("1");
var p = factory.MakeProduct("2");
var t = factory.MakeGeneric<Product>("3");
В данном случае абстрактная фабрика становится конфигурируемой, с её помощью можно создавать объект любого или заданного типа (в данном случае IProduct).Применимость паттерна
Абстрактная фабрика представляет собой слой для полиморфного создания семейства объектов. Её использование подразумевает обязательное наличие двух составляющих: 1) семейства объектов и 2) возможности замены создаваемого семейства объектов во время исполнения.
Иногда необходимость полноценной абстрактной фабрики очевидна с самого начала, но обычно лучше начать с наиболее простого решения и добавить гибкость лишь в случае необходимости.
Источник: Тепляков С. "Паттерны проектирования на платформе .NET." — СПб.: Питер, 2015. Глава 9.
День триста шестьдесят девятый. #ЗаметкиНаПолях
ASP.NET MVC 5.
HTML Helpers. Начало
HTML helpers (помощники) - это методы, которые вы можете вызывать на свойстве
Каждое представление Razor наследует свойство
Методы расширения используются по двум причинам:
1. Они доступны только тогда, когда пространство имён метода расширения находится в области видимости. Все методы расширения MVC для
2. Вы можете создавать собственные методы расширения для замены или дополнения встроенных помощников.
Помощники существуют для любых HTML элементов, используемых в формах:
-
Тем же способом помощники можно использовать в строго типизированных представлениях. Однако для этого больше подойдут строго типизированные помощники. Они отличаются от обычных наличием суффикса For и принимают первым параметром лямбда-выражение для выбора свойства модели. Например, в строго типизированном представлении для отображения класса
Продолжение следует…
Источник: Jon Galloway “Professional ASP.NET MVC 5”. – John Wiley & Sons Inc., 2014. Глава 5.
ASP.NET MVC 5.
HTML Helpers. Начало
HTML helpers (помощники) - это методы, которые вы можете вызывать на свойстве
Html представления для генерации HTML-разметки. Их цель - облегчить создание представления. Например, помощник BeginForm можно использовать для создания тега формы для формы поиска (вместо конструкции using можно использовать помощник EndForm, закрывающий форму):@using (Html.BeginForm("Search", "Home", FormMethod.Get)) {
<input type="text" name="q" />
<input type="submit" value="Search" />
}
Скорее всего будет выведена та же разметка, что и в предыдущем посте. Однако за кулисами помощник координирует свою работу с механизмом маршрутизации для создания правильного URL-адреса, поэтому код более устойчив к изменениям и при развертывании приложения.Каждое представление Razor наследует свойство
Html из своего базового класса. Свойство Html имеет тип System.Web.Mvc.HtmlHelper<T>, где T - это тип модели для представления (по умолчанию dynamic). Однако метод BeginForm, как и большинство других, определён как метод расширения.Методы расширения используются по двум причинам:
1. Они доступны только тогда, когда пространство имён метода расширения находится в области видимости. Все методы расширения MVC для
HtmlHelper находятся в пространстве имен System.Web.Mvc.Html (которое находится в области видимости благодаря ссылке на него в файле Views/web.config). Вы можете удалить его.2. Вы можете создавать собственные методы расширения для замены или дополнения встроенных помощников.
Помощники существуют для любых HTML элементов, используемых в формах:
-
Label – метка label
- BeginForm, EndForm – форма form
- TextBox – поле для ввода input type=”text”
- TextArea – многострочное поле textarea
- CheckBox - флажок input type=”checkbox”
- RadioButton – переключатель input type=”radio”
- DropDownList – выпадающий список select
- ListBox – список с множественным выбором select multiple
- Hidden – скрытое поле input type=”hidden”
- Password – поле пароля input type=”password”
Большинство помощников для полей проверяют наличие значений для отображения в коллекции ViewData (ViewBag). Например, если в методе действия задать:ViewBag.Price = 10.0;а в представлении использовать
@Html.TextBox("Price")
то будет выведен следующий HTML код:<input id="Price" name="Price" type="text" value="10" />Это также работает со свойствами объектов, помещённых в
ViewData:ViewBag.Product = new Product { Title=”Book”, Price=11 }
…
@Html.TextBox("Product.Title")
@Html.TextBox("Product.Price")
Строго типизированные помощникиТем же способом помощники можно использовать в строго типизированных представлениях. Однако для этого больше подойдут строго типизированные помощники. Они отличаются от обычных наличием суффикса For и принимают первым параметром лямбда-выражение для выбора свойства модели. Например, в строго типизированном представлении для отображения класса
Product:@model MyStore.Models.Productможно использовать строго типизированные помощники:
@Html.TextBox(m => m.Title)Преимуществами использования строго типизированных помощников являются доступность IntelliSense, проверка ошибок во время компиляции и упрощенный рефакторинг (если вы измените имя свойства в вашей модели, Visual Studio может автоматически изменить код в представлении).
@Html.TextBox(m => m.Price)
Продолжение следует…
Источник: Jon Galloway “Professional ASP.NET MVC 5”. – John Wiley & Sons Inc., 2014. Глава 5.
День триста семидесятый. #ЗаметкиНаПолях
ASP.NET MVC 5.
HTML Helpers. Окончание
Помощники и Метаданные модели
Кроме поиска данных внутри
Шаблонизированные Помощники
Шаблонизированные помощники строят HTML, используя метаданные и шаблон. Метаданные включают в себя информацию о значении модели (его имя и тип), а также метаданные модели (добавляются с помощью аннотаций или поставщика метаданных). В качестве шаблонизированных помощников выступают
Используя шаблонизированные помощники, вы просите среду выполнения подобрать наиболее подходящий элемент для отображения или редактирования. Например,
Помощники
Помощники по Рендерингу
Помощники по рендерингу создают ссылки на другие ресурсы внутри приложения, а также частичные представления.
Html.ActionLink и Html.RouteLink
Метод
Источник: Jon Galloway “Professional ASP.NET MVC 5”. – John Wiley & Sons Inc., 2014. Глава 5.
ASP.NET MVC 5.
HTML Helpers. Окончание
Помощники и Метаданные модели
Кроме поиска данных внутри
ViewData, помощники также используют доступные метаданные модели. Например, если свойство модели пометить атрибутом DisplayName:public class Product {
[DisplayName("Название")]
public string Title { get; set; }
…
}
а в представлении использовать помощник@Html.Label("Title")
то будет выведен следующий код HTML:<label for="Title">Название</label>Помощник запрашивает среду выполнения, доступны ли какие-либо метаданные модели для свойства
Title, и среда выполнения предоставляет информацию из атрибута DisplayName. Более подробно об атрибутах модели в следующих постах.Шаблонизированные Помощники
Шаблонизированные помощники строят HTML, используя метаданные и шаблон. Метаданные включают в себя информацию о значении модели (его имя и тип), а также метаданные модели (добавляются с помощью аннотаций или поставщика метаданных). В качестве шаблонизированных помощников выступают
Html.Display (Html.DisplayFor) и Html.Editor (Html.EditorFor), а также их аналоги для целой модели Html.DisplayForModel и Html.EditorForModel.Используя шаблонизированные помощники, вы просите среду выполнения подобрать наиболее подходящий элемент для отображения или редактирования. Например,
EditorFor сгенерирует тот же код HTML, что и TextBoxFor. Однако, его можно настроить с помощью аннотаций. Например, следующая аннотация:[DataType(DataType.MultilineText)]Приведёт к тому, что
public string Title { get; set; }
EditorFor сгенерирует многострочное поле textarea.Помощники
DisplayForModel и EditorForModel создают HTML-код для целой модели. Используя их, вы можете добавлять новые свойства в модель и мгновенно видеть изменения в пользовательском интерфейсе, не внося никаких изменений в представления.Помощники по Рендерингу
Помощники по рендерингу создают ссылки на другие ресурсы внутри приложения, а также частичные представления.
Html.ActionLink и Html.RouteLink
Метод
ActionLink визуализирует гиперссылку на другой метод действия или контроллер. Он использует API маршрутизации для создания URL-адреса. @Html.ActionLink("Ссылка", "AnotherAction")
Это производит следующую разметку для маршрута по умолчанию:<a href="/Home/AnotherAction">Ссылка</a>Помощник
RouteLink следует тому же шаблону, но также принимает имя маршрута и не имеет аргументов для контроллера и метода действия:@Html.RouteLink("Ссылка", new {action="AnotherAction"})
Html.Partial и Html.RenderPartialPartial визуализирует частичное представление. Как правило, оно содержит общую разметку, которую вы хотите отобразить в нескольких представлениях:@Html.Partial("ProductDisplay")
Здесь указано только имя представления. Среда выполнения ищет нужное представление, используя все доступные механизмы. Кроме того, методу можно передать модель и коллекцию ViewData.RenderPartial похож на Partial, но он пишет код непосредственно в выходной поток. По этой причине RenderPartial нужно помещать внутрь блока кода. Следующие две строки приведут к одинаковому выводу в выходной поток:@{ Html.RenderPartial("ProductDisplay"); }
@Html.Partial("ProductDisplay")
Html.Action и Html.RenderActionAction и RenderAction аналогичны Partial и RenderPartial. Но, тогда как Partial отображает код из другого представления, Action, выполняет другой метод контроллера и отображает его результат. Action предлагает больше гибкости, потому что метод контроллера может построить другую модель и использовать другой контекст:[ChildActionOnly]В представлении:
public ActionResult Menu() {
var menu = GetMenuFromSomewhere();
return PartialView(menu);
}
@Html.Action("Menu")
Обратите внимание, что метод-действие Menu помечен атрибутом ChildActionOnly. Атрибут не позволяет среде выполнения вызывать метод напрямую через URL. Он может быть вызван только через Action или RenderAction. Атрибут ChildActionOnly не требуется, но обычно рекомендуется для дочерних методов-действий.Источник: Jon Galloway “Professional ASP.NET MVC 5”. – John Wiley & Sons Inc., 2014. Глава 5.