Eu tenho um abstract class A
que declara um método abstrato doStuff
. Atualmente, existem muitas classes que herdam A
e implementam doStuff
.
As instâncias da classe são inicializadas em tempo de execução via com AFactory
base 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 A
necessidades.
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, é
AFactory
claro) 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)
emA.doStuff(AParams params)
.AParams
pode conter os parâmetros necessários edoStuff
pode 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á
X
lançandoException
esse código), decidi perguntar mesmo assim, desculpe se isso é um duplicado.
Editar 1 :
- Esclarecimento: preciso passar um argumento específico da subclasse para o
doStuff
mé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.
doStuff
método?EntryPoint
vamos chamá-lo,main
que então chama algunsInterpreter
que 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 porUserInput
(que infelizmente não posso alterar).Respostas:
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.
fonte
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).
fonte
A abordagem usual em casos como este (Commandish patternish) é passar parâmetros adicionais no construtor. No seu caso, isso significa que a adição
otherArgument
deB
durante a construção.Mudar a lógica pode abrir algumas opções. Por exemplo, movendo doStuff para AParams:
Como alternativa, você pode engolir seu orgulho e verificar com
instanceof
o loop e definirotherArgument
manualmente antes de ligardoStuff
.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.
fonte