Refatorando uma classe abstrata existente e seus parâmetros


8

Eu tenho um abstract class Aque declara um método abstrato doStuff. Atualmente, existem muitas classes que herdam Ae implementam doStuff.

As instâncias da classe são inicializadas em tempo de execução via com AFactorybase na entrada do usuário. Originalmente, todas as classes tinham o mesmo parâmetro único (a entrada do usuário). Mas agora eu tenho um parâmetro adicional que apenas uma nova classe que herda Anecessidades.

Então, detalhando, pensei na seguinte lógica:

  • A classe de intérpretes que gera instâncias com base na entrada do usuário (usando, é AFactoryclaro) não estava ciente desse parâmetro extra.

    • Tentar inseri-lo no intérprete de classe seria muito estranho, porque eu teria que saber quando passá-lo à fábrica, o que anula todo o propósito de ter uma fábrica em primeiro lugar.
    • Enviá-lo às cegas para a fábrica, esperando que possa fazer algo com isso, também parece bastante feio.
  • Minha solução atual: Enquanto isso eu decidi refactor A.doStuff(Param param)em A.doStuff(AParams params).

    AParamspode conter os parâmetros necessários e doStuffpode ignorá-los se não estiverem interessados ​​neles. Isso também me parece um pouco estranho e me impede de enviar estruturas no WIN32API que podem conter muitos parâmetros inúteis e feios e não gosto disso.

Existe uma maneira mais elegante de abordar esse problema? Ou algum padrão de design que eu negligenciei e resolve isso?

Notas :

  • Estamos usando o Java 1.7
  • Os nomes das turmas são bobos, a fim de enfatizar a questão do design teórico, eles têm nomes indicativos e significativos normais na realidade :)
  • Pesquisei bastante, mas depois de descobrir que é muito difícil pesquisar na Web questões teóricas abstratas específicas (em vez de por que está Xlançando Exceptionesse código), decidi perguntar mesmo assim, desculpe se isso é um duplicado.

Editar 1 :

  • Esclarecimento: preciso passar um argumento específico da subclasse para o doStuffmétodo.

EDIT 2 :

  • Como não entendi completamente a intenção de Kilian Foth, escrevi um pseudo-código Java para me ajudar a explicar melhor o problema / entender sua solução. Assim:

    Este é um esqueleto do meu problema.

    Este é um esqueleto da minha solução.

    Isso é o que eu acho que poderia ser a solução da Kilian Foth, mas eu não tenho certeza.


Você pode esclarecer se o seu problema é que você precisa adicionar um argumento específico ao seu método de fábrica para uma subclasse específica ou é necessário passar um argumento específico da subclasse para o doStuffmétodo?
Martin Wickman

@MartinWickman A resposta é: preciso passar um argumento específico da subclasse para o método doStuff. Obrigado por mencionar isso, peço desculpas por não ter sido suficientemente claro, mas acho que agora é melhor :). Eu editei minha pergunta ...
Scis

Parece-me que você encontrou algo semelhante ao Builder nas soluções às quais vinculou (que é o que eu fiz - eu nunca tinha ouvido falar do Builder, mas apenas codifiquei algo que fazia o que precisava) Faz).
Amy Blankenship

Você realmente precisa passar o parâmetro para doStuff ou o valor do parâmetro é conhecido quando você cria o objeto? Além disso, de onde vêm os parâmetros extras?
Aaron Kurtzhals

@AaronKurtzhals Como escrevi no arquivo-esqueleto "problem", atualmente o valor do parâmetro extra é conhecido como EntryPointvamos chamá-lo, mainque então chama alguns Interpreterque atualmente não recebem o parâmetro extra como parâmetro e a fábrica também. O parâmetro extra vem de outro tipo de entrada do usuário que não é descrito por UserInput(que infelizmente não posso alterar).
Scis

Respostas:


9

O objetivo de uma fábrica é ocultar o fato de que você pode obter objetos de classes ligeiramente diferentes. Portanto, se alguns desses objetos precisarem de certos dados e outros não ...

  • Ou eles não são semelhantes o suficiente para serem produzidos pela mesma fábrica. Então você precisa ter mais de uma fábrica e tomar a decisão mais cedo do que está fazendo atualmente.

  • Ou são semelhantes o suficiente para que o cliente não se importe com o que recebe. Então você não pode esperar que o cliente se preocupe em enviar os dados extras ou não. Daqui resulta que eles sempre devem ser aprovados, mas a fábrica às vezes os ignora sem incomodar o cliente com esses detalhes de implementação. Qualquer outra coisa sobrecarregaria o cliente com a própria distinção que a fábrica deveria ocultar.


Bem, eles são semelhantes o suficiente :) mas não tenho certeza se entendi sua solução. Você pode visualizar a pergunta editada (tentei fazer um esqueleto mostrando o problema e as diferentes abordagens) e me dizer se minha interpretação está correta ou não.
SIC

2

Eu cuido disso usando algo como um Construtor que contém várias fábricas. O Construtor recebe hashes que contêm as fábricas para fazer vários tipos de objetos, e ele analisará o hash e recuperará a fábrica correta com base em qualquer critério.

Por exemplo, eu tenho vários tipos de perguntas e tudo isso pode ser feito por alguma implementação de um IQuestionFactory. A maioria das implementações de IQuestionFactory são subclasses de BaseQuestionFactory e elas recebem XML que representa uma pergunta e a analisam de acordo com as regras da pergunta, retornando algumas subclasses de BaseQuestion.

Algumas perguntas precisam de mais informações, como se for uma pergunta de preenchimento de formulário, pode haver uma seção do XML que contém as perguntas que definem os campos que são usados ​​no formulário. As Fábricas que fazem essas perguntas implementam IEnhancedQuestionFactory, e o construtor verifica a Fábrica que recupera do QuestionFactoryRegistry e verifica se implementa essa Interface. Caso isso aconteça, ele passa o XML completo do arquivo que continha as perguntas, além do XML individual que vai para o método createQuestion.

Para mostrar o quão flexível isso pode ser, algumas das implementações do IQuestionFactory são simplesmente shells que contêm várias fábricas de perguntas e podem observar o XML recebido e, em seguida, chamar uma fábrica interna e retornar o que for necessário. Usamos isso quando um arquivo XML contém vários tipos de perguntas.

No entanto, parece que você precisa de algo mais parecido com o modo como construímos Exercícios (que são essencialmente Controladores envolvidos em uma coleção de Perguntas), em que o hash (ExerciseFactoryMap) é configurado para retornar uma fábrica padrão na maioria das vezes, mas em alguns casos onde tiver uma fábrica específica registrada, ela retornará. E nós temos uma fábrica específica que criará uma subclasse Exercise que possui uma propriedade adicional e possui a capacidade adicional de examinar o XML e encontrar as informações necessárias para preencher essa propriedade.

Então, eu concordo com Killian Foth que o objetivo de uma fábrica é ocultar os detalhes de implementação de como o objeto está sendo construído, mas não há nada que diga que você não pode combinar várias fábricas de maneira criativa (por exemplo, uma fábrica que contém outras fábricas que fazem o trabalho real).


2
  • A abordagem usual em casos como este (Commandish patternish) é passar parâmetros adicionais no construtor. No seu caso, isso significa que a adição otherArgumentde Bdurante a construção.

  • Mudar a lógica pode abrir algumas opções. Por exemplo, movendo doStuff para AParams:

    for (String arg : listOfArgs) {
        AParams p = AParams.create(arg, otherArgument));
        for (A a : listOfA) {
            p.doStuff(a); // Let AParams to the lifting depending on type of A
        }
    }
  • Como alternativa, você pode engolir seu orgulho e verificar com instanceofo loop e definir otherArgumentmanualmente antes de ligar doStuff.

Se o exposto acima não for possível, você não terá escolha, exceto fazer o que está fazendo (ampliando o argumento do parâmetro). Não analise demais essas coisas.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.