É OK para ter objeto 'ganchos' instanciação na classe base?
-
02-07-2019 - |
Pergunta
Eu criei minha própria implementação de árvore para e vêm-se com duas classes, uma classe 'base' que é um nó de árvore genérica que está repleto de lógica e outra classe que estende aquela que é mais especializado.
Na minha classe base certos métodos envolvem instanciar novos nós de árvore (por exemplo, a adição de crianças). Estes instantations são lógica dentro (em um loop aninhado, digamos) que torna a lógica difícil de separar do instantation.
Então, se eu não substituir essas instantations na classe específica o tipo errado de nó será criado. No entanto, eu não faço deseja para substituir esses métodos porque eles também continha lógica compartilhada que não deve ser duplicada!
O problema pode ser resumido a isto:
public class Foo {
public String value() { return "foo"; }
public Foo doStuff() {
// Logic logic logic..
return new Foo();
}
}
class Bar extends Foo {
public String value() { return "bar"; }
}
new Bar().doStuff().value(); // returns 'foo', we want 'bar'
A primeira coisa que me veio à cabeça teria um 'criar gancho' que as classes estendendo poderia substituir:
public Foo createFooHook(/* required parameters */) {
return new Foo();
}
Agora. enquanto ele era um bom primeiro pensamento, há um mau cheiro saindo de que o código algo terrível. Há algo de muito ... errado sobre isso.
É como cozinhar enquanto naked-- parece perigoso e desnecessário .
Assim, como você lidar com esta situação?
Solução
Assim, depois de receber minha cópia do Design Patterns e abri-lo para o que eu estou bastante certo é a primeira vez que eu descobri o que eu quero.
É o chamado Factory Method e é principalmente um ajuste perfeito. Ainda é um pouco feio, porque o meu super-classe (Foo
no exemplo acima) não é abstrato que significa que subclasses não são obrigados a implementar o gancho.
Isso pode ser corrigido com um pouco de refatoração, porém, e eu vou acabar com algo no sentido de:
abstract class AbstractFoo {
public String value() { return "Foo"; }
public AbstractFoo doStuff() {
// Logic logic logic
return hook();
}
protected abstract AbstractFoo hook();
}
class Foo extends AbstractFoo {
protected AbstractFoo hook() { return new Foo(); }
}
class Bar extends AbstractFoo {
public String value() { return "Bar"; }
protected AbstractFoo hook() { return new Bar(); }
}
new Bar().doStuff().value(); // Returns 'Bar'!
Outras dicas
Além do padrão de fábrica, eu tomaria um olhar para o padrão Composite - ele tende a dar-se bem a trabalhar com uma fábrica em situações baseadas em árvores
.Eu não acho que há uma abordagem melhor. Só tome cuidado para não chamar esses ganchos do construtor.