2017-01-20 2 views
1

Простите зашумленность вопроса, позвольте мне объяснить себя.Как сделать код форматирования без ущерба для принципа DRY в java + PDFBox?

Я создал PDFGenerator, используя PDFBox. PDF составляет около 9 страниц, фактический файл PDFGenerator.java - это монстр с почти 4k строками кода, большая часть кода которого является постоянным расположением пикселов текста (ов) внутри PDF.

Текущая версия (v1) включает в себя 2 основные переменные, источник питания и выхлоп. Таким образом, для каждой строки чего-то есть значение подачи и значение выхлопа.

Все это прекрасно работает, и я очень доволен процессом всего поколения. Однако теперь v2 пришел, и клиент хочет создать либо источник питания, либо как.

В этом заключается моя проблема с принципом DRY. Теоретически код для обоих уже существует. И единственное, что меняется, когда оно одно или другое, - это позиционирование текста, который теперь центрируется между двумя столбцами.

Пример: Оба (в настоящее время генерируется)

Атрибуты ............. ......... Поставка Выхлопная

высота .. 5 .................... 5

Ширина ........................... 5 .................... 5

Пример: один или другой

Атрибуты ........................ Поставка .........

Высота ....... ............................. 5 ............

Ширина ..................................... 5 ............ ...

Вот это блок, который генерирует одну строку:

pdContentStream.beginText(); 
    pdContentStream.setFont(boldFont, BOLD_FONT_SIZE); 
    pdContentStream.newLineAtOffset(TEXT_BEGIN, currentYCoord); 
    pdContentStream.showText(messageSource.getMessage("pdf.value.TDVentilator", null, this.locale)); 
    pdContentStream.endText(); 

    pdContentStream.beginText(); 
    pdContentStream.setFont(boldFont, BOLD_FONT_SIZE); 
    pdContentStream.newLineAtOffset(SUPPLY_BEGIN, currentYCoord); 
    pdContentStream.showText(messageSource.getMessage("pdf.supply", null, this.locale)); 
    pdContentStream.endText(); 

    pdContentStream.beginText(); 
    pdContentStream.setFont(boldFont, BOLD_FONT_SIZE); 
    pdContentStream.newLineAtOffset(EXHAUST_BEGIN, currentYCoord); 
    pdContentStream.showText(messageSource.getMessage("pdf.exhaust", null, this.locale)); 
    pdContentStream.endText(); 

Помните, что такого рода блоки повторяются на протяжении всего процесса генерации. Теперь возникает моя проблема с DRY.

Первое, что приходит мне на ум, заключается в том, чтобы экспортировать текущий код в функцию, используемую только для генерации обоих, и создать (скопировать/вставить) вторую функцию, которая используется для одного или другого. Но большая часть кода повторила бы это, делая это (с одним меньшим блоком, так как у нас есть только одна выходная переменная, а не две).

Другой способ, которым я могу думать, - создать if() перед каждым блоком кода, если этот случай примет этот блок, если этот случай примет этот блок. Еще раз, DRYness не существует (поскольку то же самое, если бы приходилось перед каждым блоком кода).

Мой вопрос: что, в общем, было бы лучшим способом? Я не против, если монстр снова вырастет с 4k до 8k строк кода, но если есть более простой (лучший) способ сделать это, я все уши.

Приветствия :)

+0

Вам не нужно устанавливать шрифт каждый раз, только если он изменяется. И вам не нужно делать beginText/endText каждый раз, однако обратите внимание, что ваши значения смещения, переданные в 'newLineAtOffset', относятся к предыдущему смещению. (первый из которых равен 0,0). Если вы выведете меньше, то файл PDF результата будет меньше, что хорошо, если вы храните их или отправляете на странице http. –

+1

Для ваших модульных тестов (вы, надеюсь, выполняете модульные тесты), я рекомендую вам выполнять рендеринг ваших PDF-файлов и сравнивать результаты изображения. Таким образом, вы можете быть уверены, что PDF-файлы остаются неизменными после вашего рефакторинга. См. TestPDFToImage.java, как вдохновение. –

+0

Aye mate, конечно, я делаю блок-тесты * кашель кашля * :) Интересная вещь, чтобы отметить там (может быть, это поможет кому-то когда-нибудь). Я провел классический тест сравнения файлов, чтобы проверить, была ли копия PDF-файла той же, что и одна, и она продолжала метать ошибки, даже если они были абсолютно одинаковыми. Оказывает, что PDF каждый раз устанавливает новый идентификатор, этот идентификатор можно статически установить через «pdfDocument.setDocumentId (1)»; После этого испытания не прошли никакой проблемы. Конечно, статический идентификатор установлен только для тестирования, для его развертывания он является сгенерированным как обычно. –

ответ

4

Глядя на ваш код:

pdContentStream.beginText(); 
pdContentStream.setFont(boldFont, BOLD_FONT_SIZE); 
pdContentStream.newLineAtOffset(EXHAUST_BEGIN, currentYCoord); 
pdContentStream.showText(messageSource.getMessage("pdf.exhaust", null, this.locale)); 
pdContentStream.endText(); 

только часть, которую я вижу по-другому является первым параметром дано messageSource.getMessage().

Таким образом, ваш рефакторинга, вероятно, начать с введения:

public void prepareContent(Whatever pdContentStream, String message) { 
    pdContentStream.beginText(); 
    pdContentStream.setFont(boldFont, BOLD_FONT_SIZE); 
    pdContentStream.newLineAtOffset(EXHAUST_BEGIN, currentYCoord); 
    pdContentStream.showText(messageSource.getMessage(message, null, this.locale)); 
    pdContentStream.endText(); 
} 

И тогда ваш главный код сводится к:

prepareContent(pdContenStream, "pdf.value.TDVentilator"); 
prepareContent(pdContenStream, "... 

и так далее. Затем: вы, вероятно, поместите этот материал в свой класс, в котором вы делаете поле pdContentStream; чтобы избавиться от необходимости этого параметра для каждого вызова.

После этого следует лучше изучить «упорядочивание» этих строк. Там нет смысла в написании:

foo("bla"); 
foo("blub"); 

Вместо этого вы раздвинуть эти ценности, как «pdf.value.TDVentilator» в Список; чтобы затем использовать итерировать списки/наборы/что угодно, чтобы получить требуемую информацию оттуда.

Короче говоря: вы не выращиваете монстров. Вы даже не позволяете им существовать. Код, который вы показываете, уже является суровым нарушением DRY, который должен быть абсолютно не быть терпимым!

+0

Спасибо за помощь, идея использовать список (или, точнее говоря, карту) была идеальной. Я упаковал тексты на карту и через итерацию легко достал целые страницы, созданные из 20 строк кода. Мне также удалось уменьшить монстра с более чем 4 тыс. До примерно 1 тыс. Линий :) Я понятия не имею, что было, хотя моя голова, когда я писал исходный код, но я определенно знаю, что теперь не повторю ошибку. –

+0

Вы очень приветствуетесь – GhostCat

Смежные вопросы