Лучше или преимущества в разных способах кодирования похожих функций - PullRequest
0 голосов
/ 02 декабря 2011

Я пишу код для GUI (на C ++), и сейчас я занимаюсь организацией текста в строках. Одна из проблем, с которыми я сталкиваюсь, состоит в том, что код становится очень длинным и запутанным, и я начинаю сталкиваться с сценарием ^ 2, где для каждой опции, которую я добавляю для представления текстов, количество функций, которые я должен написать это квадрат этого. Пытаясь справиться с этим, пришел конкретный выбор дизайна, и я не знаю лучшего метода или степени преимуществ или недостатков между ними:

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

Эти функции необходимо скопировать и переписать для левого, правого или центрированного текста с разным потоком, поэтому любой выбранный мной дизайн будет повторяться три раза.

По сути, я мог бы продолжить то, что у меня сейчас есть, это два отдельных метода для обработки этих различных действий, или я мог бы объединить их в одну функцию, в которой есть операторы if, чтобы определить, следует ли отображать текст или рисунок. если текст переполнен.

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

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

// РЕДАКТИРОВАТЬ: Исходный код //

Функция 1:

void GUITextLine :: renderLeftShifted (const GUIRenderInfo & renderInfo) { если (m_renderLines.empty ()) возвращение;

Uint iL = 0;

Array2t<float> renderCoords;
renderCoords.s_x = renderInfo.s_offset.s_x + m_renderLines[0].s_x;
renderCoords.s_y = renderInfo.s_offset.s_y + m_y;
float remainingPixelsInLine = m_renderLines[0].s_y;

for (Uint iTO= 0;iTO != m_text.size();++iTO)
{
    if(m_text[iTO].s_pixelWidth <= remainingPixelsInLine)
    {
        string preview = m_text[iTO].s_string;

        m_text[iTO].render(&renderCoords);
        remainingPixelsInLine -= m_text[iTO].s_pixelWidth;
    }

    else
    {
        FSInternalGlyphData intData = m_text[iTO].stealFSFastFontInternalData();

        float characterWidth = 0;

        Uint iFirstCharacterOfRenderLine = 0;

        for(Uint iC = 0;;++iC)
        {
            if(iC == m_text[iTO].s_string.size()) 
            {
                // wrap up
                string renderPart = m_text[iTO].s_string;
                renderPart.erase(iC, renderPart.size());
                renderPart.erase(0, iFirstCharacterOfRenderLine);
                m_text[iTO].s_font->renderString(renderPart.c_str(), intData,
                    &renderCoords);
                break;
            }

            characterWidth += m_text[iTO].s_font->getWidthOfGlyph(intData,
                m_text[iTO].s_string[iC]);

            if(characterWidth > remainingPixelsInLine) 
            {
                // Can't push in the last character
                // No more space in this line

                // First though, render what we already have:

                string renderPart = m_text[iTO].s_string;
                renderPart.erase(iC, renderPart.size());
                renderPart.erase(0, iFirstCharacterOfRenderLine);
                m_text[iTO].s_font->renderString(renderPart.c_str(), intData,
                    &renderCoords);


                if(++iL != m_renderLines.size())
                {
                    remainingPixelsInLine = m_renderLines[iL].s_y;
                    renderCoords.s_x = renderInfo.s_offset.s_x + m_renderLines[iL].s_x;

                    // Cool, so now try rendering this character again
                    --iC;
                    iFirstCharacterOfRenderLine = iC;
                    characterWidth = 0;
                }
                else
                {

                    // Quit

                    break;
                }
            }
        }
    }
}

// Done! }

Функция 2:

vector GUITextLine :: recalculateWrappingContraints_LeftShift () { m_pixelsOfCharacters = 0;

float pixelsRemaining = m_renderLines[0].s_y;

Uint iRL = 0;

// Go through every text object, fiting them into render lines
for(Uint iTO = 0;iTO != m_text.size();++iTO)
{
    // If an entire text object fits in a single line
    if(pixelsRemaining >= m_text[iTO].s_pixelWidth)
    {
        pixelsRemaining -= m_text[iTO].s_pixelWidth;
        m_pixelsOfCharacters += m_text[iTO].s_pixelWidth;
    }

    // Otherwise, character by character
    else
    {
        // Get some data now we don't get it every function call
        FSInternalGlyphData intData = m_text[iTO].stealFSFastFontInternalData();

        for(Uint iC = 0; iC != m_text[iTO].s_string.size();++iC)
        {
            float characterWidth = m_text[iTO].s_font->getWidthOfGlyph(intData, '-');

            if(characterWidth < pixelsRemaining)
            {
                pixelsRemaining -= characterWidth;
                m_pixelsOfCharacters += characterWidth;
            }

            else // End of render line! 
            {
                m_pixelsOfWrapperCharacters += pixelsRemaining; // we might track how much wrapping px we use

                // If this is true, then we ran out of render lines before we ran out of text. Means we have some overflow to return
                if(++iRL == m_renderLines.size())
                {
                    return harvestOverflowFrom(iTO, iC);
                }

                else
                {
                    pixelsRemaining = m_renderLines[iRL].s_y;
                }
            }
        }

    }
}

vector<GUIText> emptyOverflow;
return emptyOverflow; }

Таким образом, render () в основном принимает renderCoordinates в качестве параметра и получает из него глобальную позицию, из которой он должен рендерить. calcWrappingConstraints вычисляет, сколько текста в объекте занимает выделенное пространство, и возвращает этот текст как функцию.

m_renderLines - это std :: vector структуры с двумя числами с плавающей точкой, где .s_x = где может начинаться рендеринг, а .s_y = насколько велико пространство для рендеринга - нет, по сути это ширина 'renderLine', а не там, где она заканчивается.

m_text - это std :: vector объектов GUIText, которые содержат строку текста и некоторые данные, такие как стиль, цвет, размер и т. Д. Он также содержит в s_font ссылку на объект шрифта, который выполняет рендеринг, вычисляя ширину глифа, т. Д.

Надеюсь, это прояснит ситуацию.

Ответы [ 2 ]

1 голос
/ 02 декабря 2011

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

Я сделал нечто подобное, когда продублировал элемент управления макетом потока WinForms для MFC. Я имел дело с двумя типами объектов: фиксированными (ваши фотографии и т. Д.) И автоматическими (ваши слова).

В приведенном вами примере я могу перечислить общие части вашего примера.

Запись строки (направление)

  • bool TestPlaceWord (direction) // возвращает false, если не может поместить слово рядом с предыдущим словом
  • bool WrapPastObject (direction) // возвращает false, если выходит за пределы строки
  • bool WrapLine (direction) // возвращает false, если ему не хватает места для новой строки.

Каждый из них будет выполняться независимо от того, в каком направлении вы находитесь.

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

1 голос
/ 02 декабря 2011

Как насчет реализации шаблона Visitor ?Похоже, это то, что вы ищете.

...