Existe um padrão de design para manipular quando o código depende do subtipo de dois objetos

Tentarei ser o mais explícito possível, caso haja uma solução melhor para o meu problema do que responder à minha pergunta.

Estou trabalhando em c #.

Eu tenho um modelo de relatório que pode incluir qualquer número de 'recursos' ativados. Um recurso pode ser uma tabela de informações, um gráfico de barras / torta, uma lista etc. Estou gerando o relatório como um arquivo de texto ou um PDF (possivelmente outras opções no futuro).

Até agora eu tenho umIFeature interface e alguns tipos de recursos que a implementam:ChartFeature, ListFeature, etc. Li a lista de recursos ativados no banco de dados e passo cada um para um método junto com o ID de dados e o método retorna um preenchidoIFeature do tipo apropriado.

Eu também tenho umIReportWriter interface queTextReportWriter e PdfReportWriter implementar. Essa interface possui um método:AddFeature(IFeature).

O problema é queAddFeature em cada escritor acaba parecendo:

public void AddFeature(IFeature)
{
    InsertSectionBreakIfNeeded();

    if(IFeature is TableFeature)
    {
        TableFeature tf = (TableFeature)feature;
        streamWriter.WriteLine(tf.Title);
        for(int row=0; row < tf.Data.First.Length; row++)
        {
            for(int column=0; i < tf.Data.Length; i++)
            {
                if(i != 0)
                {
                    streamWriter.Write("|");
                }
                streamWriter.Write(feature.Data[column][row]);
            }
        }
    }
    else if(IFeature is ListFeature)
    {
        ListFeature lf = (ListFeature)feature;
        streamWriter.Write(lf.Title + ": ");
        bool first = true;
        foreach(var v in lf.Data)
        {
            if(!first)
            {
                streamWriter.Write(", ");
            }
            else
            {
                first = false;
            }
            streamWriter.Write(v);
        }
    }
    ...
    else
    {
        throw new NotImplementedException();
    }
    sectionBreakNeeded = true;
}

No gravador de PDF, o acima seria modificado para gerar células de tabela em PDF, caixas de texto e assim por diante.

Isso parece feio. Eu gosto um pouco melhor comoAddFeature(ListFeature){...}, AddFeature(ChartFeature) porque pelo menos o tempo de compilação é verificado, mas, na prática, apenas move o problema agora para fora se o IReportWriter que estou chamandoif(feature is ...).

Mover o código de exibição para o recurso apenas inverte o problema, pois seria necessário saber se ele deveria escrever texto sem formatação ou PDF.

Alguma sugestão, ou estou melhor apenas usando o que tenho e ignorando meus sentimentos?

Edit: Preenchido algumas das condições para dar às pessoas uma idéia melhor do que está acontecendo. Não se preocupe muito com o código exato desses exemplos; acabei de escrever isso em cima da minha cabeça.

questionAnswers(4)

yourAnswerToTheQuestion