Статьи

Общедоступные статические литералы … не являются решением для дублирования данных

У меня есть new String(array,"UTF-8")в одном месте и точно такой же код в другом месте в моем приложении. На самом деле, я могу иметь это во многих местах. И каждый раз я должен использовать эту "UTF-8"константу для создания Stringмассива байтов. Было бы очень удобно определить его где-нибудь и использовать повторно, как это делает Apache Commons; увидетьCharEncoding.UTF_8(Есть много других статических литералов там). Эти ребята подают плохой пример! publicstatic«свойства» так же плохи, как и служебные классы .

Сияющий (1980) Стэнли Кубрика
© Сияющий (1980) Стэнли Кубрика

Вот о чем я говорю, а именно:

package org.apache.commons.lang3;
public class CharEncoding {
  public static final String UTF_8 = "UTF-8";
  // some other methods and properties
}

Теперь, когда мне нужно создать Stringиз байтового массива, я использую это:

import org.apache.commons.lang3.CharEncoding;
String text = new String(array, CharEncoding.UTF_8);

Допустим, я хочу преобразовать Stringв байтовый массив:

import org.apache.commons.lang3.CharEncoding;
byte[] array = text.getBytes(CharEncoding.UTF_8);

Выглядит удобно, верно? Это то, что думают дизайнеры Apache Commons (одна из самых популярных, но просто ужасных библиотек в мире Java). Я призываю вас думать по-другому. Я не могу сказать вам, чтобы вы прекратили использовать Apache Commons, потому что у нас просто нет лучшей альтернативы (пока!). Но в своем собственном коде не используйте публичные статические свойства — никогда. Даже если этот код может показаться вам удобным, это очень плохой дизайн.

Причина, по которой они очень похожи на служебные классы с открытыми статическими методами, — это неразрывные жестко закодированные зависимости. Как только вы используете это CharEncoding.UTF_8, ваш объект начинает зависеть от этих данных, и его пользователь (пользователь вашего объекта) не может разорвать эту зависимость. Вы можете сказать, что это ваше намерение, в случае "UTF-8"константы — убедиться, что Юникод используется специально и исключительно. В этом конкретном примере это может быть правдой, но посмотрите на это с более глобальной точки зрения.

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

String text = new UTF8String(array);

Это псевдокод, так как Java-дизайнеры сделали Stringфинал класса, и мы не можем его расширить и создать UTF8String, но вы поняли идею. В реальном мире это будет выглядеть так:

String text = new UTF8String(array).toString();

Как видите, мы инкапсулируем константу «UTF-8» где-то внутри класса UTF8String, и ее пользователи не имеют представления о том, как именно происходит преобразование «байтового массива в строку».

Внедряя UTF8String, мы решили проблему дублирования букв UTF-8. Но мы сделали это надлежащим объектно-ориентированным способом — мы инкапсулировали функциональность внутри класса и позволили каждому создавать его объекты и использовать их. Мы решили проблему дублирования функций, а не только дублирования данных.

Размещение данных в одном общем месте ( CharEncoding.UTF_8) не решает проблему дублирования; на самом деле это еще хуже, в основном потому, что побуждает всех дублировать функциональность, используя один и тот же фрагмент общих данных.

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