Composicao versus Heranca

Otimo artigo para o basico do problema!

http://www.artima.com/designtechniques/compoinh.html

Qual a opiniao de voces?

Depois de ler o Design Patterns, e ainda mais agora lendo o Effective Java, eu digo NAO a heranca, apenas em casos de absoluta e total necessidade.

Estou assustadissimo com a quantidade de problemas que a heranca pode trazer. Ok, pode quebrar suas classes filhas se ela mudar, mas o MAIOR problemas eh justamente quando voce muda a superclasse, e por sorte, nao quebra as filhas! Ai voce comeca a ter bugs em runtime. Terrivel…

Cara, uma opinião baseada apenas no artigo que vc passou…

Eu não acho que chegar ao extremismo de dizer “não”, simplesmente, seja uma boa. O artigo me passou uma impressão de que “ah, se vc fizer errado, vai ter problemas lá na frente”. Pô, mas qq estrutura de classes que vc não desenhar direito vc vai ter problemas depois…

Eu fico com as considerações finais do autor, na página 5 do artigo, onde ele diz como escolher um ou outro. É óbvio que se utilizar de herança simplesmente para reutilização ou polimorfismo, as chances de encrenca são maiores. Usemos OO onde deve ser utilizado, e não porque é bonito!!!

Té+Ver

Não!!!

Eu digo não à herança, e até agora já fui salvo umas 3 vezes de cagadas incríveis “por sorte”…

Herança só é bom quando vc quer polimorfismo. Só. No Java, vc ainda tem uma alternativa ótima para a herança: interfaces e wrappers.

Na verdade, eu acho que só uso herança simples pra implementar Strategy e apenas se eu preciso de estados específicos, ou quando eu vou aproveitar muito mais do que escrever (no caso de fazer um componente swing, eu extendo JPanel e pronto).

Mesmo no strategy, eu normalmente tenho uma interface e uma mãe abstrata implementando os defaults, como acontece com Action e tantas outras.

Tenho, inclusive, um exemplo de uma herança que não deu certo no Shob (meu prj de objetos distribuídos), na parde de commlayer. Em vez de delegar o envio e a recepção das mensagens, eu fiz uma superclasse que sabe fazer isso, e as subclasses sabem montar e desmontar as mensagens. Cagada, pq agora eu quero fazer um esquema que não transmita apenas por sockets, mas por quanquer Stream, e vou ter que mexer muito.

[]s

“Herança só é bom quando vc quer polimorfismo. Só. No Java, vc ainda tem uma alternativa ótima para a herança: interfaces e wrappers.” (Tiago M Silveira)

Touché… Herança de classes concretas são muito perigosas porque mudanças nas classes-base podem afetar todo o funcionamento das filhas. Um desastre. O que eu costumo fazer para implementar polimorfismo é seguir a idéia do Tiago: um montão de interfaces e algumas classes abstratas, sendo que os métodos concretos (aqueles que são implementados diretamente na classe abstrata) eu os marco como “final”, por segurança :slight_smile: .

Meus 2 cents:

Uma mistura bem feita de composição e herança geralmente é o mais legal de se ter num modelo de objetos. Supondo que vc esta escrevendo um sistema de arquivos em java, voce poderia ter um esquema mais ou menos assim:

abstract class FileSystemObject implements Ownable class File extends FileSystemObject class Folder extends FileSystemObject implements FileContainer abstract class Link extends FileSystemObject class SymbolicLink extends Link class HardLink extends Link

Quase nunca a boa solucao de arquitetura eh “NUNCA use x, SEMPRE use y”, mas sim “use x e y com sabedoria”

Acho que o assunto é extenso, e podemos ter um aproaching com várias visões…

Do ponto de vista da OOP, herança e polimorfismo quando aplicadas corretamente agilizam muito a contrução de software.

Do ponto de vista de UML (OOAD), devemos pensar bem antes de escolher usar a herança…

Via de regra, se um objeto compartilha atributos e funcionalidades de outro, e fazem parte do mesmo domíno de negócio, a herança é indicada. Entretando, se a intenção é reaproveitar serviços de uma determinada classe, mas a nova classe não faz parte do domínio, então indico a composição.

Assim concluo, mais vale um modelo bem desenhado e abstraído de um determinado escopo, usando Interfaces, Abstract Classes, Concrete Classes (Parent ou Child), do que sair fazendo código e ter de refazer depois…

OO, é uma solução poderosa e robusta, e o bom senso deve ser sempre usado…

[quote=“cv”]Meus 2 cents:
Quase nunca a boa solucao de arquitetura eh “NUNCA use x, SEMPRE use y”, mas sim “use x e y com sabedoria”[/quote]

Verdade!! Até dei a impressão de que eu não uso herança…

andei olhando meu código e reparei que realmente tem pouquíssima herança, mesmo pra implementar Strategy…

Sabe o que eu percebi que cresceu muito em frequencia nos meus códigos?? Listeners… nem sei como chama-se esse padrão, mas tem ajudado muito. Geralmente é uma dupla com uma LinkedList, uma interface BlaBlaListener e um par de addBlaBlaListener(BlaBlaListener) e removeBlaBlaListener(BlaBlaListener)

Ah, também diminuíram bastante as responsabilidades de cada classe de dois anos pra cá… antes, uma mesma classe sabia fazer muitas coisas, hoje em dia uma classe que guarda estado praticamente só faz isso, enquanto as que manipulam eventos praticamente só fazem isso, antes eu colocava meio que tudo junto, as classes eram poderosas…

Não sei exatamente o impacto na qualidade, já que ainda não me aconteceu de pegar um código de 97 pra rescrever… :slight_smile:

[]s

Ate por curiosidade…

Alguem tem alguma sugestao sobre livros ou links de bons sites sobre OO??

valew

Aproveitando que esse topico foi resgatado das profundezas, eu acabei achando um post bem legal, e bem depois desse topico, no blog do Carlos Perez:

http://www.manageability.org/blog/stuff/taxonomy_of_object_composition

[quote=“Carlos Perez”]:arrow: Overriding - The ability of the modification to override methods defined in the base. In M(B), M’s definitions hide B’s definitions with the same name. Self-invocations within B ignore redefinitions in M.

:arrow: Transparent redirection - The ability to transparently redirect Bs this to denote M(B) within the composition.

:arrow: Acquisition - The ability to use definitions in B as if these were local methods in M(B) (transparent forwarding of services from M to B).

:arrow: Subtyping - The promise that M(B) fulfills the contract specified by B, or that M(B) can be used everywhere B is expected.

:arrow: Polymorphism - The ability to (dynamically or statically) apply M to any subtype of B.
[/quote]

Toda vez que tenho a chance de uma herança eu NÃO RECUSO…
Infelizmente eu sou materialista e uma graninha e imóveis a mais não fazem mal hehehe

:lol: