Как вы справляетесь со строками, которые имеют структуру? - PullRequest
5 голосов
/ 10 февраля 2009

Предположим, у меня есть объект, представляющий человека, с методами получения и установки для адреса электронной почты этого человека. Определение метода установки может выглядеть примерно так:

setEmailAddress(String emailAddress)
    {
    this.emailAddress = emailAddress;
    }

В этом случае вызов person.setEmailAddress(0) вызовет ошибку типа, но вызов person.setEmailAddress("asdf") не произойдет, хотя asdf никоим образом не является действительным адресом электронной почты.

По моему опыту, так называемые строки - это почти никогда произвольных последовательностей символов без ограничений по длине или формату. На ум приходят URI - как и уличные адреса, как и номера телефонов, как и имена ... Вы понимаете. Тем не менее, эти типы данных чаще всего хранятся как «просто строки».

Возвращаясь к моему личному объекту, предположим, что я изменяю setEmailAddress() примерно так

setEmailAddress(EmailAddress emailAddress)
    // ...

где EmailAddress - это класс ..., конструктор которого принимает строковое представление адреса электронной почты. Получил ли я что-нибудь?

ОК, так что адрес электронной почты - плохой пример. Как насчет класса URI, который принимает строковое представление URI в качестве параметра конструктора и предоставляет методы для управления этим URI - установки пути, извлечения параметра запроса и т. Д. Важность правильности исходной строки становится важной.

Итак, я спрашиваю всех вас, как вы справляетесь со строками, которые имеют структуру? И как вы объясняете свои структурные ожидания в своих интерфейсах?

Спасибо.

Ответы [ 9 ]

9 голосов
/ 10 февраля 2009

«Струны со структурой» являются признаком общего кодового запаха « Примитивная одержимость ».

Средство защиты должно внимательно следить за дублированием в коде, который проверяет или манипулирует частями этих структур. При первом намеке на дублирование - но не раньше - извлеките класс, который инкапсулирует структуру, и найдите там валидации и запросы.

2 голосов
/ 10 февраля 2009

Добро пожаловать в мир программирования!

Не думаю, что ваш вопрос является признаком ошибки с вашей стороны. Скорее, это основная проблема , которая появляется во многих ипостасях мира программирования. Строки, которые имеют некоторую структуру и имеют значение , означающее , передаются между различными подсистемами приложения, и каждая подсистема может выполнять только большой анализ и проверку.

Проблема проверки адреса электронной почты, например, довольно сложная. Например, регулярные выражения, предлагаемые разными людьми для принятия адреса электронной почты, обычно бывают либо «слишком жесткими» (не все принимаются), либо «слишком свободными» (принимают незаконные вещи). Первый гугл-хит для 'regex' адрес электронной почты '', например, говорит:

Регулярное выражение, которое я получаю большинство отзывов, не говоря уже о «баге» отчеты, это тот, который вы найдете прямо на домашней странице этого сайта: \ b [A-Z0-9 ._% + -] + @ [A-Z0-9 .-] +. [A-Z] {2,4} \ b Проанализируйте это регулярное выражение с помощью RegexBuddy. Это регулярное выражение, я претензия, соответствует любому адресу электронной почты. Наиболее обратной связи я получаю опровергает, что заявить, указав один адрес электронной почты что это регулярное выражение не соответствует.

Дело в том, что действительный адрес электронной почты является или не является сложной проблемой, которую данная программа может или не может решить. Проблема URL-адресов еще хуже, особенно с учетом возможности вредоносных URL-адресов.

В идеале вы можете иметь библиотеку или системный вызов, который решает проблемы такого рода, вместо того, чтобы делать что-либо самостоятельно (Microsoft Windows вызывает настраиваемое диалоговое окно, чтобы позволить пользователю выбрать или создать файл, поскольку проверка имен файлов - это еще хитрая проблема). Но вы не всегда можете рассчитывать на наличие соответствующего системного вызова для данной «значимой строки».

Я бы сказал, что нет общего решения проблемы строк со структурой. Скорее, это основная проблема, которая появляется прямо при разработке приложения. В процессе сбора требований для вашего приложения вы должны определить, какие данные будет принимать приложение и насколько значимыми будут эти данные для приложения . И вот тут все становится сложнее, поскольку вы можете заметить, что приложение может расти такими способами, о которых ваш босс или клиент не мог подумать - или приложение может фактически расти такими способами, о которых никто из вас не думал. Таким образом, приложение должно быть немного более гибким, чем то, что кажется минимальным, НО только немного. Это также не должно быть настолько гибким, что вы увязли.

Теперь, если вы решите, что вам нужно проверить / интерпретировать и т. Д. Данную строку, размещение этой строки в объекте или хэше может быть хорошим подходом - это один из известных мне способов убедиться, что ваш интерфейс понятен. Но самое сложное - решить, сколько вам нужно валидации или интерпретации.

Принятие этих решений, таким образом, является искусством - здесь нет никаких догматических ответов.

2 голосов
/ 10 февраля 2009

Это довольно распространенная проблема, подпадающая под заголовок ' validation ' - существует много способов проверки ввода текста пользователем, одним из наиболее распространенных является Regular Expressions .

Вы можете также рассмотреть возможность использования встроенного System.Net.MailAddress класса для этого, так как он обеспечивает проверку адресов электронной почты.

1 голос
/ 10 февраля 2009

Регулярные выражения - ваш друг, когда дело доходит до форматирования строк. Вы также можете хранить каждую часть отдельно в структуре, чтобы избежать использования регулярных выражений каждый раз, когда вы захотите их использовать. например,

struct EMail
{
    String BeforeAt = "johndoe123";
    String AfterAt = "gmail.com";
}

Struct URL
{
    String Protocol = "http";
    String Domain = "sub.example.com";
    String Path = "stuff/example.html";
}
1 голос
/ 10 февраля 2009

Строки - это строки. Если вам нужно, чтобы ваши строки были умнее, чем обычные строки, то было бы неплохо разобрать их в структурный объект, который вы описываете. Я бы использовал для этого регулярное выражение.

0 голосов
/ 10 февраля 2009

Лично я не думаю, что в этом случае необходимо строго вводить строку адреса электронной почты, так как EmailAddress.

Чтобы создать свой адрес электронной почты, вам рано или поздно придется сделать что-то вроде:

EmailAddress(String email)

или сеттер

SetEmailAddress(String email)

В обоих случаях вам придется проверять ввод строки электронной почты, что возвращает вас к первоначальной проблеме проверки.

Я бы, как указывали другие, использовал регулярные выражения.

Наличие класса EmailAddress было бы полезно, если вы планируете впоследствии выполнить определенные операции с хранимой информацией (например, получить только доменное имя, и тому подобное).

0 голосов
/ 10 февраля 2009

Я согласен с вызовами для строгой типизации объекта, но для тех случаев, когда вы анализируете строку или объект, ответ прост: обработка ошибок.

Существует два основных способа обработки ошибок: исключения и условия возврата. Обычно, если вы ожидаете получить плохо сформированные данные, вы должны вернуть сообщение об ошибке. Для случаев, когда ввод не ожидается, то я бы бросил исключение. Например, вы можете указать неправильно сформированный адрес электронной почты, например, «bob» вместо «bob@gmail.com». Однако для нулевых значений вы можете выдать исключение, так как вам не следует пытаться сформировать электронное письмо из нулевого значения.

Возвращаясь к вашему вопросу, я думаю, что вы получаете что-то, кодируя структуру в объект. В частности, вам нужно только проверить, что строка представляет действительный адрес электронной почты в одном конкретном месте, например в конструкторе. В другом месте ваш код может предполагать, что объект EmailAddress является допустимым, и вам не нужно полагаться на хитрые классы с именами, такими как «EmailHelper» или некоторыми другими.

0 голосов
/ 10 февраля 2009

Лично мне нравится идея строгой типизации, поэтому, если бы я все еще работал на таких языках, я бы использовал стиль вашего второго примера. Единственное, что я мог бы изменить, это использовать более «похожую на приведение» структуру, такую ​​как EmailAddressFromString(String), которая генерировала новый объект EmailAddress (или подбирала подгонку, если строка была неправильной), поскольку немного фанат приложения венгерской нотации.

Кстати, вся эта проблема довольно хорошо освещена Джоэлом в http://www.joelonsoftware.com/articles/Wrong.html, если вам интересно.

0 голосов
/ 10 февраля 2009

Что ж, если вы хотите сделать несколько разных вещей с объектом EmailAddress, эти другие действия не должны проверять, является ли это действительным адресом электронной почты, так как объект EmailAddress гарантированно имеет допустимую строку. Вы можете сгенерировать исключение в конструкторе или использовать фабричный метод или любой другой подход «One True Methodology».

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...