Eu tenho um problema conceitual com uma implementação adequada de código que parece exigir herança múltipla, que não seria um problema em muitas linguagens OO, mas como o projeto é para Android, não existe algo como múltiplo extends
.
I têm um grupo de actividades, derivadas a partir de diferentes classes de base, tais como simples Activity
, TabActivity
, ListActivity
, ExpandableListActivity
, etc. Também I tem alguns fragmentos de código que eu necessidade de colocar em onStart
, onStop
, onSaveInstanceState
, onRestoreInstanceState
e outros processadores de eventos normais em todas as actividades.
Se eu tiver uma única classe base para todas as atividades, colocaria o código em uma classe derivada intermediária especial e criaria todas as atividades estendendo-o. Infelizmente, esse não é o caso, porque existem várias classes base. Mas colocar as mesmas partes do código em várias classes intermediárias não é um caminho, imho.
Outra abordagem poderia ser criar um objeto auxiliar e delegar todas as chamadas dos eventos mencionados acima ao auxiliar. Mas isso requer que o objeto auxiliar seja incluído e que todos os manipuladores sejam redefinidos em todas as classes intermediárias. Portanto, não há muita diferença para a primeira abordagem aqui - ainda há muitas duplicatas de código.
Se uma situação semelhante ocorresse no Windows, eu subclasseia a classe base (algo que "corresponde" à Activity
classe no Android) e capturaria as mensagens apropriadas (em um único local).
O que pode ser feito em Java / Android para isso? Eu sei que existem ferramentas interessantes, como instrumentação Java ( com alguns exemplos reais ), mas não sou um guru de Java e não tenho certeza se vale a pena tentar neste caso específico.
Se eu perdi outras soluções decentes, mencione-as.
ATUALIZAR:
Para aqueles que podem estar interessados em resolver o mesmo problema no Android, encontrei uma solução simples. Existe a classe Application , que fornece, entre outras coisas, a interface ActivityLifecycleCallbacks . Faz exatamente o que eu preciso, permitindo-nos interceptar e agregar algum valor em eventos importantes para todas as atividades. A única desvantagem desse método é que ele está disponível a partir do nível 14 da API, o que não é suficiente em muitos casos (o suporte ao nível 10 da API é um requisito típico hoje).
decordator pattern
. Este é um último recurso, que, na verdade, demonstra o que eu preferiria evitar - duplicação de código. Aceitarei sua resposta, se nenhuma outra ideia interessante aparecer. Posso usar genéricos para generalizar o código dos "intermediários"?Eu acho que você está tentando evitar o tipo errado de duplicação de código. Acredito que Michael Feathers escreveu um artigo sobre isso, mas infelizmente não consigo encontrá-lo. A maneira como ele descreve é que você pode pensar no seu código como tendo duas partes como uma laranja: a casca e a polpa. A casca é o material como declarações de método, declarações de campo, declarações de classe, etc. A polpa é o material contido nesses métodos; a implementação.
Quando se trata de DRY, você deseja evitar duplicar a polpa . Mas frequentemente no processo você cria mais casca. E tudo bem.
Aqui está um exemplo:
Isso pode ser refatorado para isso:
Adicionamos muita casca nessa refatoração. Mas, o segundo exemplo tem um limpador muito mais limpo
method()
com menos violações DRY.Você disse que gostaria de evitar o padrão do decorador porque leva à duplicação de código. Se você olhar a imagem nesse link, verá que ela duplicará apenas a
operation()
assinatura (por exemplo: casca). Aoperation()
implementação (pasta) deve ser diferente para cada classe. Acho que seu código ficará mais limpo como resultado e terá menos duplicação de pasta.fonte
Você deve preferir composição a herança. Um bom exemplo é o " padrão " IExtension na estrutura do .NET WCF. Além disso, você tem 3 interfaces, IExtension, IExtensibleObject e IExtensionCollection. Você pode então compor os diferentes comportamentos com um objeto IExtensibleObject adicionando instâncias de IExtension à sua propriedade Extension IExtensionCollection. Em java, deve ser algo parecido com isso, não que você precise criar sua própria implementação IExtensioncollection que chama os métodos de anexar e desanexar quando itens estão sendo adicionados / removidos. Observe também que cabe a você definir os pontos de extensão na sua classe extensível. O exemplo usa um mecanismo de retorno de chamada do tipo evento:
Essa abordagem tem o benefício da reutilização de extensão, se você conseguir extrair pontos de extensão comuns entre suas classes.
fonte
processor.addHandler(console)
fornecido queConsoleProcessor
implementaria a própria interface de retorno de chamada. O padrão de "extensão" parece uma combinação devisitor
edecorator
, mas é necessário neste caso?A partir do Android 3.0, pode ser possível resolver isso de maneira elegante usando um fragmento . Os fragmentos têm seus próprios retornos de chamada do ciclo de vida e podem ser colocados dentro de uma Atividade. Não tenho certeza se isso funcionará para todos os eventos.
Outra opção que também não tenho certeza (com falta de profundo conhecimento do Android) pode ser usar um Decorator da maneira oposta que o k3b sugere: crie um
ActivityWrapper
cujos métodos de retorno de chamada contenham seu código comum e depois encaminhe para umActivity
objeto empacotado (seu classes de implementação reais) e faça com que o Android inicie esse wrapper.fonte
É verdade que o Java não permite herança múltipla, mas você pode simulá-la mais ou menos fazendo com que cada uma das subclasses SomeActivity estenda a classe Activity original.
Você terá algo como:
fonte