Я наткнулся на запись в блоге, в которой не рекомендуется использовать Strings в Java для того, чтобы в вашем коде отсутствовала семантика, предлагая вместо этого использовать классы тонкой оболочки. Это примеры «до» и «после», приведенные в данной статье для иллюстрации:
public void bookTicket(
String name,
String firstName,
String film,
int count,
String cinema);
public void bookTicket(
Name name,
FirstName firstName,
Film film,
Count count,
Cinema cinema);
По своему опыту чтения блогов по программированию я пришел к выводу, что 90% - это чепуха, но мне остается задуматься, является ли это обоснованным аргументом. Почему-то мне это не кажется правильным, но я не могу точно определить, что не так со стилем программирования.
Ответы:
Инкапсуляция предназначена для защиты вашей программы от изменений . Будет ли изменяться представление Имени? Если нет, то вы напрасно тратите время и YAGNI подает заявку.
Изменить: я прочитал сообщение в блоге, и у него есть принципиально хорошая идея. Проблема в том, что он слишком далеко продвинулся. Что - то вроде
String orderId
это очень плохо, потому что по- видимому"!"£$%^&*())ADAFVF
, не является допустимымorderId
. Это означает, чтоString
представляет намного больше возможных значений, чем допустимыхorderId
s. Однако для чего-то подобного aname
вы не можете предсказать, что может быть или не быть действительным именем, а любоеString
является допустимымname
.В первом случае вы (правильно) сокращаете возможные входные данные до только допустимых. Во втором случае вы не добились сужения возможных допустимых входных данных.
Изменить еще раз: рассмотрим случай неверного ввода. Если вы напишите «Гарет Гобулькок» в качестве своего имени, это будет выглядеть глупо, это не будет концом света. Если вы введете неверный OrderID, скорее всего, он просто не будет работать.
источник
Name
, вы не можете случайно передать другое несвязанное значение String. Там, где вы ожидаетеName
,Name
компилируется только воля, и строка «Я должен вам 5 долларов» не может быть случайно принята. (Обратите внимание, что это никак не связано с проверкой имен!)Это просто безумие :)
источник
var p = new Point(x: 10, y:20);
Кроме того, Cinema не похожа на строку. Я бы понял, если бы мы имели дело с физическими величинами, такими как давление, температура, энергия, где единицы отличаются, а некоторые не могут быть отрицательными. Автору блога нужно попробовать функционал.Я согласен с автором, в основном. Если есть какое-либо поведение, свойственное полю, такое как проверка идентификатора заказа, то я бы создал класс для представления этого типа. Его второе замечание еще более важно: если у вас есть набор полей, которые представляют какое-то понятие, например адрес, то создайте класс для этого понятия. Если вы программируете на Java, вы платите высокую цену за статическую типизацию. Вы также можете получить все, что можете.
источник
Не делай этого; это усложнит вещи, и вам это не нужно
... это ответ, который я написал бы здесь 2 года назад. Теперь, однако, я не так уверен; фактически, в последние месяцы я начал мигрировать старый код в этот формат не потому, что мне нечего делать, а потому, что он мне действительно нужен для реализации новых функций или изменения существующих. Я понимаю автоматическое неприятие, которое другие здесь видят в этом коде, но я думаю, что это то, что заслуживает серьезной мысли.
Выгоды
Главным преимуществом является возможность изменять и расширять код. Если вы используете
вместо того, чтобы просто передавать пару целых чисел - что, к сожалению, делают многие интерфейсы, - потом становится гораздо проще добавить другое измерение. Или измените тип на
double
. Если вы используетеList<Author> authors
илиList<Person> authors
вместоList<String> authors
этого позже, становится намного проще добавлять больше информации к тому, что представляет автор. Записывая это так, я чувствую, что я констатирую очевидное, но на практике я сам много раз виноват в использовании строк таким образом, особенно в тех случаях, когда это не было очевидно в начале, тогда мне нужно больше, чем строка.В настоящее время я пытаюсь реорганизовать какой-либо список строк, который переплетен в моем коде, потому что мне нужно больше информации там, и я чувствую боль: \
Кроме того, я согласен с автором блога в том, что он несет больше семантической информации , облегчая понимание читателю. В то время как параметрам часто присваиваются значимые имена, и они получают специальную строку документации, это часто не относится к полям или локальным объектам.
Последним преимуществом является безопасность типов по понятным причинам, но на мой взгляд, это мелочь здесь.
Недостатки
Это займет больше времени, чтобы написать . Написать небольшой класс быстро и легко, но не легко, особенно если вам нужно много этих классов. Если вы каждые три минуты останавливаетесь, чтобы написать какой-нибудь новый класс-обёртку, это также может сильно помешать вашей концентрации. Однако я хотел бы подумать, что такое состояние усилий обычно возникает только на первом этапе написания любого фрагмента кода; Обычно я быстро получаю хорошее представление о том, какие сущности должны быть задействованы.
Он может включать в себя множество избыточных сеттеров (или конструкций) и геттеров . Автор блога приводит действительно уродливый пример
new Point(x(10), y(10))
вместоnew Point(10, 10)
, и я хотел бы добавить, что использование может также включать такие вещи, какMath.max(p.x.get(), p.y.get())
вместоMath.max(p.x, p.y)
. И длинный код часто считают трудным для чтения, и это справедливо. Но, честно говоря, я чувствую, что много кода перемещает объекты, и только избранные методы создают его, и еще меньше нуждаются в доступе к его мельчайшим деталям (что в любом случае не является OOPy).дискуссионный
Я бы сказал , помогает ли это или нет с читаемостью кода спорна. Да, больше семантической информации, но больше кода. Да, легче понять роль каждого местного специалиста, но труднее понять, что вы можете с ним сделать, если не пойдете и не прочитаете его документацию.
Как и в большинстве других школ программирования, я думаю, что это вредно для здоровья. Я не вижу, чтобы я когда-либо разделял координаты x и y, чтобы они были разных типов. Я не думаю, что
Count
это необходимо, когдаint
должно быть достаточно. Мне не нравитсяunsigned int
использование в C - хотя теоретически это хорошо, оно просто не дает вам достаточно информации, и оно запрещает расширять ваш код позже для поддержки этого магического -1. Иногда вам нужна простота.Я думаю, что сообщение в блоге немного экстремально. Но в целом я узнал из мучительного опыта, что основная идея, лежащая в его основе, состоит из правильных вещей.
У меня глубокое отвращение к чрезмерно спроектированному коду. Я действительно делаю. Но использовал правильно, я не думаю, что это чрезмерное проектирование.
источник
Хотя это отчасти излишне, я часто думаю, что большинство вещей, которые я видел, было недостаточно разработанным.
Это не просто «Безопасность». Одна из действительно приятных особенностей Java - то, что она очень помогает вам запоминать / выяснять, что нужно / что ожидает любой вызов библиотечного метода.
НАИБОЛЬШАЯ (безусловно) библиотека Java, с которой я работал, была написана кем-то, кто очень любил Smalltalk и моделировал библиотеку GUI после того, как она работала как smalltalk - проблема в том, что каждый метод брал один и тот же базовый объект, но на самом деле не мог ИСПОЛЬЗОВАТЬ все, к чему может быть приведен базовый объект, так что вы вернулись к предположению, что передать в методы, и не знали, потерпели ли вы неудачу до времени выполнения (что-то, с чем я имел дело, приходилось сталкиваться каждый раз работал в с).
Другая проблема - если вы передаете строки, целые, коллекции и массивы без объектов, все, что у вас есть, - это шары данных без смысла. Это кажется естественным, когда вы думаете с точки зрения библиотек, которые будет использовать «какое-то приложение», но при разработке целого приложения гораздо полезнее присвоить смысл (код) всем вашим данным в том месте, где они определены, и думать только в условия взаимодействия этих объектов высокого уровня. Если вы передаете примитивы вместо объектов, то вы - по определению - изменяете данные в месте, отличном от того, где они определены (это также, почему я действительно не люблю сеттеры и геттеры - та же концепция, вы работаете на данных, которые не ваши).
Наконец, если вы определяете отдельные объекты для всего, у вас всегда есть отличное место для проверки всего - например, если вы создаете объект для почтового индекса, а затем обнаруживаете, что вам необходимо убедиться, что почтовый индекс всегда включает 4-значное расширение, которое у вас есть. идеальное место, чтобы положить его.
На самом деле это не плохая идея. Размышляя об этом, я даже не уверен, что скажу, что он вообще был чрезмерно спроектирован, с ним просто работать практически во всех отношениях - единственным исключением является распространение крошечных классов, но классы Java настолько легки и просты написать, что это даже не стоимость (они могут даже быть сгенерированы).
Мне было бы очень интересно увидеть хорошо написанный Java-проект, в котором на самом деле было определено слишком много классов (где это усложняло программирование), я начинаю думать, что слишком много классов невозможно.
источник
Я думаю, что вы должны взглянуть на эту концепцию с другой отправной точки. Взгляните с точки зрения разработчика базы данных: типы, переданные в первом примере, не определяют ваши параметры уникальным способом, не говоря уже о полезном способе.
Два параметра необходимы для указания фактического покупателя, который заказывает билеты, у вас может быть два разных фильма с одинаковыми именами (например, ремейки), у вас может быть один и тот же фильм с разными именами (например, переводы). В определенной сети кинотеатров могут быть разные филиалы, так как вы будете поступать с этим последовательно и согласованно (например, используете
$chain ($city)
ли вы$chain in $city
или еще что-то и как собираетесь убедиться, что это используется на худой основе. На самом деле худшее - это указание вашего покровителя с помощью двух параметров, тот факт, что указаны имя и фамилия, не гарантирует действительного клиента (и вы не можете различить дваJohn Doe
).Ответ на это заключается в объявлении типов, но они редко будут тонкими обертками, как я покажу выше. Скорее всего, они будут функционировать как ваше хранилище данных или будут связаны с какой-то базой данных. Таким образом,
Cinema
объект, скорее всего, будет иметь имя, местоположение, и таким образом вы избавитесь от таких двусмысленностей. Если они тонкие обертки, они по стечению обстоятельств.Итак, ИМХО в блоге просто говорится «убедитесь, что вы передали правильные типы», его автор просто сделал чрезмерно ограниченный выбор, чтобы выбрать в частности базовые типы данных (что является неправильным сообщением).
Предлагаемая альтернатива лучше:
С другой стороны, я думаю, что сообщение в блоге заходит слишком далеко, оборачивая все.
Count
слишком общий, я мог бы сосчитать яблоки или апельсины с этим, добавить их, и у меня все еще есть ситуация, когда система типов позволяет мне делать бессмысленные операции. Конечно, вы можете применять ту же логику, что и в блоге, определять типыCountOfOranges
и т. Д., Но это также глупо.Что бы это ни стоило, я бы на самом деле написал что-то вроде
Короче говоря: вы не должны передавать бессмысленные переменные; единственный раз, когда вы на самом деле указываете объект со значением, которое не определяет фактический объект, это когда вы запускаете запрос (например
public Collection<Film> findFilmsWithTitle(String title)
) или когда вы собираете подтверждение концепции. Держите систему типов в чистоте, поэтому не используйте слишком общий тип (например, фильм, представленный символом aString
) или слишком ограничительный / конкретный / надуманный (например,Count
вместоint
). Используйте тип, который определяет ваш объект однозначно и однозначно, когда это возможно и жизнеспособно.редактировать : еще более короткое резюме. Для небольших приложений (например, подтверждение концепции): зачем беспокоиться о сложной конструкции? Просто используйте
String
илиint
и иди с этим.Для больших приложений: действительно ли вероятно, что у вас есть много классов, состоящих из одного поля с базовым типом данных? Если у вас мало таких классов, у вас просто есть «нормальные» объекты, ничего особенного там не происходит.
Я чувствую, что идея инкапсуляции строк ... это просто неполный проект: слишком сложный для небольших приложений, недостаточно полный для больших приложений.
источник
Для меня это то же самое, что и использование регионов в C #. Как правило, если вы чувствуете, что это необходимо для того, чтобы сделать ваш код читабельным, тогда у вас есть большие проблемы, на которые вы должны тратить свое время.
источник
Я бы сказал, что это действительно хорошая идея для языка со строго типизированной функцией типа typedef.
В Java этого нет, поэтому создание нового класса для этих вещей означает, что стоимость, вероятно, перевешивает выгоду. Вы также можете получить 80% прибыли, внимательно следя за именами переменных / параметров.
источник
Было бы хорошо, если бы IF String (end Integer и ... говоря только о String) не был окончательным, так что эти классы могли бы БЫТЬ некоторой (ограниченной) String со смыслом и все же могли бы быть отправлены какому-нибудь независимому объекту, который знает, как обрабатывать базовый тип (без разговоров туда-сюда).
И "добрые дела" этого увеличиваются, когда есть, например. ограничения на все имена.
Но при создании какого-либо приложения (не библиотеки) его всегда можно реорганизовать. Поэтому я предпочитаю начинать без него.
источник
В качестве примера: в нашей разрабатываемой в настоящее время системе существует множество различных сущностей, которые могут быть идентифицированы различными видами идентификаторов (из-за использования внешних систем), иногда даже однотипными сущностями. Все идентификаторы являются строками - поэтому, если кто-то смешивает, какой тип идентификатора должен быть передан в качестве параметра, ошибка времени компиляции не отображается, но программа будет взорвана во время выполнения. Это случается довольно часто. Поэтому я должен сказать, что основная цель этого принципа - не защищать от изменений (хотя это также и служит), а защищать себя от ошибок. И в любом случае, если кто-то разрабатывает API, он должен отражать концепции домена, поэтому концептуально полезно определять классы, специфичные для домена - все зависит от того, есть ли порядок в сознании разработчиков,
источник