Comments 66
люблю, когда все просто и доступно объясняют. минимум заумных слов, куча примеров и результат в действии :)
+7
А мне очень нравится как это сделано в django. Сейчас пытаюсь выдрать forms оттуда.
+1
А как это реализовано? Поделитесь.
0
Строго говоря, модуль django.forms не только проверяет данные, он может ещё их вводом-выводом заниматься. Например, рендерить исходную форму (обратите внимание на widget=forms.Textarea), а также указывать на ошибки ввода, предлагая их исправить (с показом введённых ранее данных).
Вот простой и довольно реальный пример на Django:
Самые простые случаи (обязательное/необязательное поле, число символов, максимум и минимум, соответствие регулярному выражению) Django умеет обрабатывать сам — надо только добавить простые параметры — «min_value», «regex», «required» и пр. Для более сложных ситуаций, можно написать свой метод вида «clean_XYZ», и Django будет использовать его для проверки поля «XYZ».
А для случаев, когда поля как-то связаны между собой (например, надо заполнить хотя бы одно из полей) — можно просто написать метод «clean», и он будет вызван на последней стадии, после проверки всех полей в отдельности. Там уже можно оценить все поля совокупно, и «вынести вердикт».
В итоге, используется форма так:
Вот простой и довольно реальный пример на Django:
from django import forms
import re
class ContactForm(forms.Form):
"Пусть это некоторая форма обратной связи - для выяснения состояния заказа"
name = forms.CharField(label=u"Ваше имя", max_length=100)
# Поле может быть необязательным для заполнения (required=False)
company = forms.CharField(label="Название вашей организации", required=False)
text = forms.CharField(label=u"Текст вопроса", widget=forms.Textarea)
email = forms.EmailField(label=u"E-mail для ответа")
order = forms.CharField(label=u"Код заказа")
def is_valid_order(self, order):
# здесь проверяется код заказа и выдаётся True или False
def clean_order(self):
"""Функция, дополнительно проверяющая поле "order". Она может
также изменить значение поля - например, отформатировав его.
В данном случае, из кода заказа исключаются начальные и конечные пробелы,
а сам заказ проверяется методом is_valid_order, включенным прямо в форму.
"""
order = self.cleaned_data['order']
order = order.strip() # Немного форматируем
if self.is_valid_order(order):
raise forms.ValidationError(u"Вы ошиблись в коде заказа.")
return order
Самые простые случаи (обязательное/необязательное поле, число символов, максимум и минимум, соответствие регулярному выражению) Django умеет обрабатывать сам — надо только добавить простые параметры — «min_value», «regex», «required» и пр. Для более сложных ситуаций, можно написать свой метод вида «clean_XYZ», и Django будет использовать его для проверки поля «XYZ».
А для случаев, когда поля как-то связаны между собой (например, надо заполнить хотя бы одно из полей) — можно просто написать метод «clean», и он будет вызван на последней стадии, после проверки всех полей в отдельности. Там уже можно оценить все поля совокупно, и «вынести вердикт».
В итоге, используется форма так:
def process_form(request):
if request.method == "POST":
form = ContactForm(request.POST)
if form.is_valid():
# Используем данные формы, например, просто выдадим их в косоль:
for key,value in form.cleaned_data.items():
print key, ":", value
# Кстати, в form.cleaned_data лежат уже не просто строки, а реальные данные
# соответствующих типов - int, datetime, unicode и т.п.
else:
form = ContactForm()
...
+3
А зачем выдирать?
Лучше просто его используйте! Ведь джанго это не только формы, но еще куча полезных и удобных вещей.
Лучше просто его используйте! Ведь джанго это не только формы, но еще куча полезных и удобных вещей.
+3
Автор, исправляй ошибки. Это не скомпилируется, так как ожидается список, а не массив.
public List GetResultCodes {
get { return resultCodes.ToArray(); }
}
public List GetResultCodes {
get { return resultCodes.ToArray(); }
}
0
Также стоит переписать
public void AddError(ResultCode code) {
isSucceedResult = false;
resultCodes.Add(code);
}
как
public void AddError(ResultCode code) {
if (!resultCodes.Contains(code))
resultCodes.Add(code);
}
чтобы не добавлять одну и ту же ошибку дважды
А также перепишите свойство
public bool IsSucceed {
get { return isSucceedResult; }
}
как
public bool IsSucceed {
get { return resultCodes.Count == 0; }
}
то есть, всё хорошо, если нет ошибок — не стоит плодить лишних флагов.
public void AddError(ResultCode code) {
isSucceedResult = false;
resultCodes.Add(code);
}
как
public void AddError(ResultCode code) {
if (!resultCodes.Contains(code))
resultCodes.Add(code);
}
чтобы не добавлять одну и ту же ошибку дважды
А также перепишите свойство
public bool IsSucceed {
get { return isSucceedResult; }
}
как
public bool IsSucceed {
get { return resultCodes.Count == 0; }
}
то есть, всё хорошо, если нет ошибок — не стоит плодить лишних флагов.
0
Исправил, спасибо. Без студии под рукой сложно писать компилируемый код)
0
И всё-таки я не это имел в виду. Во-первых, имя GetResultCodes предполагает метод, а не свойство — свойство называлось бы просто ResultCodes. Во-вторых, не возвращайте список — его можно модифицировать — возвращайте массив, так как это свойство (или метод — это вам решать) должно быть использовано только для чтения. Это очень распростанённая ошибка проектирования.
+2
ещё одна ошибка в последнем блоке кода:
public ValidationResult Validate(string userName, string userPassword)
имя метода должно быть ValidateUser.
public ValidationResult Validate(string userName, string userPassword)
имя метода должно быть ValidateUser.
0
> люди часто изобретают свои собственные велосипеды для реализации механизма валидации.
О да, Вы правы.
В ASP.NET (речь ведь о нём, раз серверная валидация?) есть встроенные валидаторы. И на клиенте работают, и на сервере. И есть CustomValidator, в котором можно реализовать что угодно. Велосипед, говорите?..
О да, Вы правы.
В ASP.NET (речь ведь о нём, раз серверная валидация?) есть встроенные валидаторы. И на клиенте работают, и на сервере. И есть CustomValidator, в котором можно реализовать что угодно. Велосипед, говорите?..
+2
> пришёл к выводу, что люди часто изобретают свои собственные велосипеды
поэтому я решил предложить свой? :)
поэтому я решил предложить свой? :)
+4
Из статьи я не понял, в чём собственно бонус от использования Composite. На мой взгляд, в приведённом примере будет проще и понятнее, если просто вызвать валидаторы по очереди, а не засовывать их в список (add) и делать Validate. Вы можете привести пример, когда предлагаемое Вами «заворачивание» действительно нужно/удобно?
Вообще, почему именно Composite? Вы хотите сделать «древовидный валидатор»? А нужно ли это?
И ещё я не понял, как подразумевается обрабатывать ошибки из GetResultCodes? Ведь теряется соответствие между ошибкой и валидатором. Неужто это будет выглядеть вроде if (result[1])...? А что будет в «древовидном» случае?
Поправьте, пожалуйста, если я что-то не так понял.
Вообще, почему именно Composite? Вы хотите сделать «древовидный валидатор»? А нужно ли это?
И ещё я не понял, как подразумевается обрабатывать ошибки из GetResultCodes? Ведь теряется соответствие между ошибкой и валидатором. Неужто это будет выглядеть вроде if (result[1])...? А что будет в «древовидном» случае?
Поправьте, пожалуйста, если я что-то не так понял.
+4
При использовании фабрики валитаров мы получаем готовый объект, состоящий из необходимых в нашем случае валидаторов. С точки зрения разработчика, для валидации данных нужно будет вызвать всего один метод Validate. А вызывать валидаторы по очереди не всегда удобно. А если их 5, 10 20? Проще 1 раз написать фабричный метод, чем постоянно писать ненужные строки кода.
Например, нужно провалидировать анкету перед сохранением в базу, которую заполнил пользователь. У вас есть фабричный метод: GetFormValidator(параметры). Дёргаете этот метод и получаете результат валидации. Всё. Я считаю, это очень удобно.
Что касается обработки ошибок, то обычно этот процесс заключается в том, чтобы уведомить пользователя о проблемах ввода. Например, слишком длинное имя пользователя, неправильный e-mail. Провалидировав данные, вы получаете плоский список всех ошибок, которые небольшим вспомогательным классом можно поставить в соответствие текстовые сообщения для уведомления.
Например, нужно провалидировать анкету перед сохранением в базу, которую заполнил пользователь. У вас есть фабричный метод: GetFormValidator(параметры). Дёргаете этот метод и получаете результат валидации. Всё. Я считаю, это очень удобно.
Что касается обработки ошибок, то обычно этот процесс заключается в том, чтобы уведомить пользователя о проблемах ввода. Например, слишком длинное имя пользователя, неправильный e-mail. Провалидировав данные, вы получаете плоский список всех ошибок, которые небольшим вспомогательным классом можно поставить в соответствие текстовые сообщения для уведомления.
0
При грамотном использовании MVC, написать набор проверок через фабричные методы прийдется так же один раз — в контроллере, отвечающем за сохранение анкеты. Ведь если у вас анкета может сохраняться в десяти местах — неужели Вы считаете, что компоновщик избавит от ошибок?
БОлее того — компоновщик не для этого придуман…
БОлее того — компоновщик не для этого придуман…
0
Немного не понял вашего комментария.
«При грамотном использовании MVC, написать набор проверок через фабричные методы прийдется так же один раз — в контроллере, отвечающем за сохранение анкеты» — нужный фабричный метод будет написан 1 раз.
«Ведь если у вас анкета может сохраняться в десяти местах — неужели Вы считаете, что компоновщик избавит от ошибок?» — от ошибок валидации избавляют валидаторы, на которые написаны хорошие тесты.
«При грамотном использовании MVC, написать набор проверок через фабричные методы прийдется так же один раз — в контроллере, отвечающем за сохранение анкеты» — нужный фабричный метод будет написан 1 раз.
«Ведь если у вас анкета может сохраняться в десяти местах — неужели Вы считаете, что компоновщик избавит от ошибок?» — от ошибок валидации избавляют валидаторы, на которые написаны хорошие тесты.
0
Я же не говорил о том, чтобы «постоянно писать ненужные строки кода». Я говорил о конкретном примере, который приведён в статье. Конкретно в этом случае, я бы не стал делать так, как показано. Видимо, не очень удачный пример, про фабричные методы лучше бы получилось :)
«Небольшой вспомогательный класс» меня пугает, как представлю себе его реализацию, учитывая уже упомянутое мной отсутствие соответствия между ошибкой и валидатором. Например, в валидатор добавили ещё один валидатор, теперь нужно идти, образно говоря, править индексы в том вспомогательном классе?
Ну и в конце концов я так и не понял, зачем всё же нужен «древовидный» Composite.
«Небольшой вспомогательный класс» меня пугает, как представлю себе его реализацию, учитывая уже упомянутое мной отсутствие соответствия между ошибкой и валидатором. Например, в валидатор добавили ещё один валидатор, теперь нужно идти, образно говоря, править индексы в том вспомогательном классе?
Ну и в конце концов я так и не понял, зачем всё же нужен «древовидный» Composite.
0
По поводу примера в статье — опять же, самое простое, что пришло в голову. Для данного случая фабрика не нужна. Если имеем сложную систему, то уже надо об этом хорошо подумать.
Что касается добавления валидаторов:
допустим, у вас в анкете появилось новое поле, которое нужно проверять. Вы создаёте валидатор, добавляете новую ошибку в класс ResultCode и добавляете его в коллекцию композитного валидатора анкеты. Всё. Никаких индексов не нужно больше править.
Что касается добавления валидаторов:
допустим, у вас в анкете появилось новое поле, которое нужно проверять. Вы создаёте валидатор, добавляете новую ошибку в класс ResultCode и добавляете его в коллекцию композитного валидатора анкеты. Всё. Никаких индексов не нужно больше править.
0
Согласен с предыдущим оратором.
Основное предназночение Composite — создание древовидных структур с возможностью единообразного перехода по всему дереву. Автор использует этот подход, только для того, чтобы представить flat structure, и никакого намека на то, что когда-нибудь валидаторы захотят стать многоуровневыми не имеется.
Как пофиксить: используйте Chain of Responsibility для организации структуры валидаторов. Вы все так же будете использовать Factory для их создания\инициализации, будет один метод validate() для дерганья, но структура объектов будет более грамотная и использоваться по назначению, не вводя в заблуждение опытных разработчиков, которые все же знают, что такое композит.
Основное предназночение Composite — создание древовидных структур с возможностью единообразного перехода по всему дереву. Автор использует этот подход, только для того, чтобы представить flat structure, и никакого намека на то, что когда-нибудь валидаторы захотят стать многоуровневыми не имеется.
Как пофиксить: используйте Chain of Responsibility для организации структуры валидаторов. Вы все так же будете использовать Factory для их создания\инициализации, будет один метод validate() для дерганья, но структура объектов будет более грамотная и использоваться по назначению, не вводя в заблуждение опытных разработчиков, которые все же знают, что такое композит.
+2
Спасибо, интересно.
0
интересно, но слова «дешего» нет в русском языке, поправьте пожалуйста
0
Мне казалось, что в любом нормальном фреймворке эта проблема уже решена. Например, в Django при создании форм можно сразу задать ограничения на поля:
То есть банальной валидацией: типо пустое поле, слишком длинное/короткое и тп. разработчик даже не должен заморачиваться.
Если нужно, что-то чуть сложнее, то добавляйте свой метод. Например, вот так можно проверить, что поле subject содержит подстроку «msg#»:
Да, валидация сделана через исключения. Вопрос только в том, что эти исключения ловит и обрабатывает сам фреймворк — вам совершенно не нужно заморачиваться над этим. Вплоть до того, что даже в неправильной форме выводит текст ошибки красным цветом прямо над нужным полем.
Зачем все это «велосипедить» руками? Не может быть, чтобы в явоввских фреймворках не было аналогичного механизма.
class ContactForm(forms.Form): subject = forms.CharField(max_length=100) message = forms.CharField() sender = forms.EmailField() cc_myself = forms.BooleanField(required=False)
То есть банальной валидацией: типо пустое поле, слишком длинное/короткое и тп. разработчик даже не должен заморачиваться.
Если нужно, что-то чуть сложнее, то добавляйте свой метод. Например, вот так можно проверить, что поле subject содержит подстроку «msg#»:
def clean_subject(self): data = self.cleaned_data['subject '] if 'msg#' not in data: raise ValidationError, 'Поле subject должно содержать номер сообщения'
Да, валидация сделана через исключения. Вопрос только в том, что эти исключения ловит и обрабатывает сам фреймворк — вам совершенно не нужно заморачиваться над этим. Вплоть до того, что даже в неправильной форме выводит текст ошибки красным цветом прямо над нужным полем.
Зачем все это «велосипедить» руками? Не может быть, чтобы в явоввских фреймворках не было аналогичного механизма.
+1
Предложенный мной метод может применятся не только для валидации данных в клиент-серверных приложениях и не толко для валидации пользовательских данных. Подобный подход, например, можно использовать для проверки внутренних объектов на соответствие правилам бизнес логики.
0
Но не все же пользуются фреймворками.
0
Да. Просто валидация пользовательских данных — один из столпов нормальной разработки, поэтому для этого уже порядком наработано хороших решений. Если их не использовать, то придется делать руками. Потеря времени.
0
Пользуются почти все, только часто сами об этом не подозревают :) Даже набор стандартных PHP-шных функций можно назвать фреймворком «из коробки». Сам PHP — это набор готовых инструментов для разработки. С остальными языками ситуация ещё более ясная. Если делается не простой CGI-скрипт, то сразу встаёт потребность в наборе из кучи специализированных функций — эскейпить HTML, работать с HTTP-заголовками, загружать файлы… Всё это уже можно назвать фреймворком. Включая то, что вы дописали сами.
0
доброго суток времени
-2
1) Приведенный способ валидации мог быть с успехом воплощен использую коллекцию (паттерн Comopsite представляет собой иерархию, что вряд-ли применимо в данном контексте)
2) Ошибка валидации бизнесс данных не есть ошибка приложения, НО исключение тоже не обязательно является ошибкой приложения. Более детальное обьяснение приводит Дж. Рихтер CLR via C# (Глава «Ислючения» «Что-же такое исключение») совертую прочитать, почень познавательно.
Кроме того. Зачастую забытый catch и в итоге падение приложение, НАМНОГО лучше забытой проверки результата возвращенного ф-цией валидации (в вашем случае проверка содержимого коллекции).
Представтье к чему может привести такая забывчивость в обоих случаях. Например при валидаци данных для валютных транзакций.
p.s. Понятие красивости, и главное, правильности в области программирования — очень тонкая материя, я бы не торопился давать общих советов, что правильно а что нет :)
2) Ошибка валидации бизнесс данных не есть ошибка приложения, НО исключение тоже не обязательно является ошибкой приложения. Более детальное обьяснение приводит Дж. Рихтер CLR via C# (Глава «Ислючения» «Что-же такое исключение») совертую прочитать, почень познавательно.
Кроме того. Зачастую забытый catch и в итоге падение приложение, НАМНОГО лучше забытой проверки результата возвращенного ф-цией валидации (в вашем случае проверка содержимого коллекции).
Представтье к чему может привести такая забывчивость в обоих случаях. Например при валидаци данных для валютных транзакций.
p.s. Понятие красивости, и главное, правильности в области программирования — очень тонкая материя, я бы не торопился давать общих советов, что правильно а что нет :)
+3
используются исключения (exceptions) на этапе бизнес валидации. Важно помнить, что ошибки валидации данных != ошибкам работы приложения;
Означает ли это, что механизм исключений нужно применять исключительно (простите за тавтологию) для обработки ошибок приложения?
+1
Исправьте в первом примере Validate на ValidateUser или наоборот.
По-существу: вы хотите сказать, что приведенный ниже велосипед получился красивее, нежели оригинал? Сомневаюсь, начали с Composite, в итоге просто грубо говоря вынесли интерфейс (Validate) и сделали обертку над коллекций валидаторов. В итоге Composite не получился, а получилась адска обертка сочетающая в себе и поведенческую логику и элементы интерфейса :)
По-существу: вы хотите сказать, что приведенный ниже велосипед получился красивее, нежели оригинал? Сомневаюсь, начали с Composite, в итоге просто грубо говоря вынесли интерфейс (Validate) и сделали обертку над коллекций валидаторов. В итоге Composite не получился, а получилась адска обертка сочетающая в себе и поведенческую логику и элементы интерфейса :)
+1
Из приведённого вами материала, я бы сделал другую вещь. Сама по себе валидация несет несколько целей:
— Проверить можно ли продолжать, к примеру регестрировать пользователя в системе.
— Если возникли ошибки, вывести какое-то уведомление.
Я здесь вижу совершенно другой подход: обернуть логику проверки правильно веденных данных в валидатор. У валидатора сделать ивент, и на этот ивент подписывать заинтересованные классы. Например какой-нибудь Класс WrongUsernameReaction, который будет выводить сообщение об ошибке, и т. д. Т. е. максимум обсервер, никаких Composite.
— Проверить можно ли продолжать, к примеру регестрировать пользователя в системе.
— Если возникли ошибки, вывести какое-то уведомление.
Я здесь вижу совершенно другой подход: обернуть логику проверки правильно веденных данных в валидатор. У валидатора сделать ивент, и на этот ивент подписывать заинтересованные классы. Например какой-нибудь Класс WrongUsernameReaction, который будет выводить сообщение об ошибке, и т. д. Т. е. максимум обсервер, никаких Composite.
0
>if (/*проверяем имя пользователя*/)
> throw new InvalidUsernameException();
Может лучше вызывать исключение внутри метода проверки. Ну, а дальше пошла какая-то ерунда, уродская замена стандартному механизму исключений, впрочем если нравятся извращения…
> throw new InvalidUsernameException();
Может лучше вызывать исключение внутри метода проверки. Ну, а дальше пошла какая-то ерунда, уродская замена стандартному механизму исключений, впрочем если нравятся извращения…
+1
А в моём примере как получается?
Идёт проверка, если она непроходит, кидается exception. В примерах, которые погуглил, очень часто так делается.
Идёт проверка, если она непроходит, кидается exception. В примерах, которые погуглил, очень часто так делается.
0
Да, исключение кидается, исключение перехватывается. Майкрософт создала определённые правила по которым всё это записывается, это как бы общая рекомендация по написанию кода и данный образец ей не следует.
Опять же в книге «Совершенный код» не советуют делать много наследуемых классов, а здесь получается такое увеличение на каждый валидатор. Не вдаваясь в подробности нужно себя спросить будет ли этих валидаторов больше семи разновидностей, и если их больше, то использовать другое решение.
>— базовый класс Validator можно заменить на интерфейс, кому как нравится;
О чём и речь, это не просто решение нравится не нравится, это совершенно разные подходы к программированию. На интерфейсах валидатор сольётся с классом, который он проверяет, используя же наследование придётся включить объект валидатора в класс, и именно он будет торчать в списке валидаторов, а это уже совсем другая история.
Опять же в книге «Совершенный код» не советуют делать много наследуемых классов, а здесь получается такое увеличение на каждый валидатор. Не вдаваясь в подробности нужно себя спросить будет ли этих валидаторов больше семи разновидностей, и если их больше, то использовать другое решение.
>— базовый класс Validator можно заменить на интерфейс, кому как нравится;
О чём и речь, это не просто решение нравится не нравится, это совершенно разные подходы к программированию. На интерфейсах валидатор сольётся с классом, который он проверяет, используя же наследование придётся включить объект валидатора в класс, и именно он будет торчать в списке валидаторов, а это уже совсем другая история.
0
«Опять же в книге «Совершенный код» не советуют делать много наследуемых классов, а здесь получается такое увеличение на каждый валидатор. Не вдаваясь в подробности нужно себя спросить будет ли этих валидаторов больше семи разновидностей, и если их больше, то использовать другое решение.»
Может быть вы не правильно поняли ту идею, что я хотел донести, либо я её некорректно донёс. Базовый класс либо интерфейс нужен для того, чтобы у всех дочерних объектов была одинаковая сигнатура для метода — запуска валидации. Что касается наследования, то давайте посмотрим на .net framework, где все производные классы и интерфейсы наследуются от Object.
Что значит «получается такое увеличение на каждый валидатор», поясните.
«О чём и речь, это не просто решение нравится не нравится, это совершенно разные подходы к программированию. На интерфейсах валидатор сольётся с классом, который он проверяет, используя же наследование придётся включить объект валидатора в класс, и именно он будет торчать в списке валидаторов, а это уже совсем другая история.»
Признаться, я не совсем понимаю данную фразу, поясните пожалуйста.
Может быть вы не правильно поняли ту идею, что я хотел донести, либо я её некорректно донёс. Базовый класс либо интерфейс нужен для того, чтобы у всех дочерних объектов была одинаковая сигнатура для метода — запуска валидации. Что касается наследования, то давайте посмотрим на .net framework, где все производные классы и интерфейсы наследуются от Object.
Что значит «получается такое увеличение на каждый валидатор», поясните.
«О чём и речь, это не просто решение нравится не нравится, это совершенно разные подходы к программированию. На интерфейсах валидатор сольётся с классом, который он проверяет, используя же наследование придётся включить объект валидатора в класс, и именно он будет торчать в списке валидаторов, а это уже совсем другая история.»
Признаться, я не совсем понимаю данную фразу, поясните пожалуйста.
0
>Что касается наследования, то давайте посмотрим на .net framework, где все производные классы и интерфейсы наследуются от Object.
Вот смотрю .NET Framework x.x и не вижу ни одного интерфейса, который бы прямо или косвенно наследовался от класса Object. Интерфейсы могут наследоваться от интерфейсов, но в итоге мы приходим к базовому интерфейсу, который не имеет базового класса Object.
>Базовый класс либо интерфейс нужен для того, чтобы у всех дочерних объектов была одинаковая сигнатура для метода — запуска валидации.
Лучше сказать, что нужен полиморфизм (из вики — полиморфизм в языках программирования — взаимозаменяемость объектов с одинаковым интерфейсом), так как ты пытаешься реализовать именно его.
Во-первых, я за то чтобы в данном случае использовать полиморфизм через интерфейсы, но не полиморфизм через наследование. В основу легла простая мысль из книги совершенный код, а именно — наследование увеличивает сложность связей.
Таким образом если встаёт вопрос использовать ли включение (containment) (в UML — агрегирование) или наследование (inheritance) (в UML — генерализация), наследование используется лишь когда исходная сущность является развитием базовой сущности, а включение, когда она содержит в себе некую сущность.
Здесь у нас полиморфизм, но выводы те же самые, а именно ни в коем случае не использовать в данном случае полиморфизм через наследование, так как наследование увеличивает сложность связей.
>Поискав на хабре топики данной тематики и погуглив, пришёл к выводу, что люди часто изобретают свои собственные велосипеды для реализации механизма валидации.
Это как раз про тебя :)
Вот смотрю .NET Framework x.x и не вижу ни одного интерфейса, который бы прямо или косвенно наследовался от класса Object. Интерфейсы могут наследоваться от интерфейсов, но в итоге мы приходим к базовому интерфейсу, который не имеет базового класса Object.
>Базовый класс либо интерфейс нужен для того, чтобы у всех дочерних объектов была одинаковая сигнатура для метода — запуска валидации.
Лучше сказать, что нужен полиморфизм (из вики — полиморфизм в языках программирования — взаимозаменяемость объектов с одинаковым интерфейсом), так как ты пытаешься реализовать именно его.
Во-первых, я за то чтобы в данном случае использовать полиморфизм через интерфейсы, но не полиморфизм через наследование. В основу легла простая мысль из книги совершенный код, а именно — наследование увеличивает сложность связей.
Таким образом если встаёт вопрос использовать ли включение (containment) (в UML — агрегирование) или наследование (inheritance) (в UML — генерализация), наследование используется лишь когда исходная сущность является развитием базовой сущности, а включение, когда она содержит в себе некую сущность.
Здесь у нас полиморфизм, но выводы те же самые, а именно ни в коем случае не использовать в данном случае полиморфизм через наследование, так как наследование увеличивает сложность связей.
>Поискав на хабре топики данной тематики и погуглив, пришёл к выводу, что люди часто изобретают свои собственные велосипеды для реализации механизма валидации.
Это как раз про тебя :)
0
Я в итоге пришел к тому, что одной валидации недостаточно, как минимум нужен еще метод принятия (Commit) это нужно, например, при загрузке файла, на первом этапе вы проверяете валидность полей (размер, расширение, etc.), а в Commit копируете файл в хранилище, прописываете связи в бд и т. п.
0
автор, тебе уважение за статью!
Продолжай в том же духе! У меня все никак руки не доходили до этой темы. В общем молодец.
Спасибо.
Продолжай в том же духе! У меня все никак руки не доходили до этой темы. В общем молодец.
Спасибо.
0
Мда… как у вас точка-нетников все сложно… Пользователи php-, ruby- и даже python- фреймворков уже давно решили эту проблему, а вы там то фабрики, то исключения придумываете…
0
Есть более красивые решения, осуществляемые средствами Аспектно-Ориентированного программирования ( ru.wikipedia.org/wiki/AOP ).
Суть в том, что сначала пишет чистая бизнес-логика без всяких там секьюрити, логгирования и т. п. Далее аспектами на методы навешивается весь нужный «служебный» функционал.
Преимущества:
— абсолютная прозрачность кода, программист видит только то что он хочет: бизнес-логика, валидация, логгирование, кэширование;
— огромная гибкость;
— возможность расширять уже существующий код, вообще не трогая его исходники.
Суть в том, что сначала пишет чистая бизнес-логика без всяких там секьюрити, логгирования и т. п. Далее аспектами на методы навешивается весь нужный «служебный» функционал.
Преимущества:
— абсолютная прозрачность кода, программист видит только то что он хочет: бизнес-логика, валидация, логгирование, кэширование;
— огромная гибкость;
— возможность расширять уже существующий код, вообще не трогая его исходники.
0
В этом подходе главное опыт. На моём первом проекте применили подобный подход к разработке, потом очень долго доводили до ума. Команда была большая и неопытная.
0
UFO just landed and posted this here
В Java это сейчас стандартизируют: jcp.org/aboutJava/communityprocess/edr/jsr303/index.html
Сделанно на аннотациях, есть группы. Довольно неплохо выходит.
Сделанно на аннотациях, есть группы. Довольно неплохо выходит.
0
Sign up to leave a comment.
Серверная валидация пользовательских данных