questão interessante sobre OO

16 respostas
V

Olá pessoal encontrei um outro tópico muito interessante sobre construção de objetos, para quem quiser dar uma olhada aí vai o link
http://www.coderanch.com/t/476548/Programmer-Certification-SCJP/certification/with-instance-initializer

16 Respostas

tiagorg

É interessante sim, reflita sobre isso e pense como pode utilizar a seu favor.

Já trabalhei num projeto que utilizávamos isto ao nosso favos, a gente extendia todas as classes do Swing fazendo-os também realizar comportamentos de persistência em beans, trabalhando num estilo parecido com JSF.

Pesquise sobre o design pattern Decorator que também trabalha sobre este cenário.

ViniGodoy

Sim, mas você não deve chamar métodos que não sejam finais no construtor. Isso porque, a parte da classe correspondente ao filho ainda não foi construída. Nenhum atributo de lá é válido e, caso o método altere algum valor de atributo, esse valor será descartado. Isso pode gerar erros dificílimos de se corrigir, sem falar em comportamento inesperado do sistema.

O padrão decorator não usa esse princípio, pois ele nem necessariamente envolve herança.

sergiotaborda

ViniGodoy:

O padrão decorator não usa esse princípio, pois ele nem sequer envolve herança.

Decorator sim envolve herança (http://en.wikipedia.org/wiki/Decorator_pattern).
Acho que vc está confundindo com Visitor (que não envolve herança e tb permite adicionar mais funcionalidades)

ViniGodoy

sergiotaborda:
ViniGodoy:

O padrão decorator não usa esse princípio, pois ele nem sequer envolve herança.

Decorator sim envolve herança (http://en.wikipedia.org/wiki/Decorator_pattern).
Acho que vc está confundindo com Visitor (que não envolve herança e tb permite adicionar mais funcionalidades)

Na maior parte das vezes, uso o decorator baseando em uma interface, não numa classe concreta. Mas realmente, no padrão descrito pelo GoF, fala-se em herança. Em todo caso, a idéia central do decorator é embutir funcionalidades usando-se para isso composição e não herança.

sergiotaborda

ViniGodoy:
sergiotaborda:
ViniGodoy:

O padrão decorator não usa esse princípio, pois ele nem sequer envolve herança.

Decorator sim envolve herança (http://en.wikipedia.org/wiki/Decorator_pattern).
Acho que vc está confundindo com Visitor (que não envolve herança e tb permite adicionar mais funcionalidades)

Na maior parte das vezes, uso o decorator baseando em uma interface, não numa classe concreta. Mas realmente, no padrão descrito pelo GoF, fala-se em herança. Em todo caso, a idéia central do decorator é embutir funcionalidades usando-se para isso composição e não herança.

O decorador tem que ser do mesmo tipo que o original. Mesmo que o original seja uma interface vc tem que implementar a mesma interface. A relação “o decorador É-UM X” é mantida, e por conseguinte a relação de herança, mesmo que vc não use a keyword extends.

O padrão usa herança no sentido que mantem a relação É-UM e o principio de substituição se aplica, não que ele usa necessáriamente extends.

ViniGodoy

sergiotaborda:
O decorador tem que ser do mesmo tipo que o original. Mesmo que o original seja uma interface vc tem que implementar a mesma interface. A relação “o decorador É-UM X” é mantida, e por conseguinte a relação de herança, mesmo que vc não use a keyword extends.

O padrão usa herança no sentido que mantem a relação É-UM e o principio de substituição se aplica, não que ele usa necessáriamente extends.

A herança do decorator existe para garantir compatibilidade da interface do decorador e o decorado. Entretanto, o padrão baseia-se extensão de funcionalidade por composição. Isso evita, por exemplo, que uma classe “JanelaComBorda” seja criada como filha da classe “Janela”, o que usaria o princípio demonstrado pelo autor do tópico, e reforça o uso da herança como mecanismo de extensão de funcionalidade.

Decorador e decorado não precisam ter qualquer relação é um. Um exemplo disso é um decorator que, por exemplo, gera estatísticas sobre o objeto decorado. A única relação entre eles seria “realizam a interface X”, o que não necessariamente implica em relação de herança. Embora a interface seja a mesma, o decorador terá um papel (por exemplo, gerar estatísticas), e o decorado outro (por exemplo, trafegar dados num canal).

tiagorg

No nosso caso nós criamos uma interface para cada componente da view e também extendemos as classes do Swing (JTextField, JButton, etc) para classes nossas que adicionam funcionalidades e que também implementam as interfaces anteriormente citadas.

Aí criamos uma classe Factory que cria os componentes view e retorna sob a interface anteriormente citada.

No caso o componente foi criado para, sob as mesmas interfaces, servir tanto para componentes Swing quando para componentes SWT. Então a gente passava por parâmetro se desejaria um componente baseado em Swing ou SWT e ele retornava o objeto sob a mesma interface.

Portanto tinhamos uma família de componentes baseados em SWT e uma família de componentes baseados em Swing. Pois eram os requisitos dos analistas do projeto até então.

Na minha opinião utilizamos sim o padrão Decorator, além de outros como Factory, Command (para as ações dos componentes botões) e Observer (para os listeners da nossa camada de persistência serem refletidos na view).

sergiotaborda

ViniGodoy:

Decorador e decorado não precisam ter qualquer relação é um. Um exemplo disso é um decorator que, por exemplo, gera estatísticas sobre o objeto decorado. A única relação entre eles seria “realizam a interface X”, o que não necessariamente implica em relação de herança. Embora a interface seja a mesma, o decorador terá um papel (por exemplo, gerar estatísticas), e o decorado outro (por exemplo, trafegar dados num canal).

LoL… então vamos lá:
Se o decorador não precisa ter relação É-UM com o decorado , porquê vc precisa que o decorador implemente a mesma interface que o decorado ?

Se a sua tese fosse verdade , Comparable poderia ser um decorador de List.

Se A implementa a interface I e B também, e B é composto de A, e B não tem nenhum método a mais que A, B não é um decorador, é um proxy.
Decorador implica que B seja A no sentido de principio de substituição de Liskov(http://en.wikipedia.org/wiki/Liskov_substitution_principle) e além disso ele tem métodos que A não tem.
Ou seja, vc pode passar B onde seria esperado um A, e além disso tem acesso a métodos que não são acessíveis em A.

Adapter, Decorator, Proxy e Façade são muito semelhantes na implementação, mas são as subtilezas que os tornam diferentes.

A relação É-UM está ligada ao principio Liskov assim como a herança, os três são principios gerais de OO.
O fato do java distinguir entre herança e implementação não é relevante pois o padrão Decorator é agnóstico à linguagem.

ViniGodoy

Estou entendo direito, ou você quer me convencer que relação de herança entre classes e implementação de interfaces significam a mesma coisa?

Duas classes completamente diferentes podem implementar a mesma interface, e estarem relacionadas única e exclusivamente por isso. Considere, por exemplo, o que faz o BufferedInputStream. Ele apenas decora um stream, dando a ele uma funcionalidade a mais, a presença de um buffer. Mas ele, por si só, não é um stream e, portanto, não se trata de herança. O mesmo vale para outras classes do java como SychronizedCollection, ou mesmo UnmodifiableList (que inclusive nega o princípio de Liskov).

Em momento nenhum eu disse que ele só poderia ter métodos de A. De onde você tirou isso? Aliás, que eu me lembre, a única imposição do decorator é que ele deve adicionar um comportamento, não que isso deva implicar necessariamente na adição de novos métodos.

Concordo. Não estou falando em uma linguagem específica, também.

ViniGodoy

A diferença entre um decorator e um proxy nem sequer é essa. O decorator foca-se em adicionar funcionalidades dinamicamente a objetos. Aliás, é essa característica dele, que digo que nega o princípio de herança, uma vez que herança envolve em ampliar a funcionalidade de classes.

Já o proxy, é relacionado servir de interface para alguém.

Até por isso, tipicamente, criamos o objeto decorado externamente, e adicionamos a ele o decorator. Enquanto o objeto proxiado geralmente é criado internamente, dentro do proxy (obviamente o proxy pode delegar essa tarefa para uma fábrica, mas normalmente fará isso dentro sua parte privada).

sergiotaborda

Estou entendo direito, ou você quer me convencer que relação de herança entre classes e implementação de interfaces significam a mesma coisa?

Para o padrão sim. Por isso que eu disse que o fato do java separar o que herança de classe do que é implementação de interfaces não pode ser usado para dizer que o decorator não usa herança.
Em scala, por exemplo, vc tem traits que não são nem interfaces nem classes, são um conceito diferente. E eles são decorators por design.

O ponto é que "o conceito de herança" está relacionada a "É-UM", sempre. Independentemente da linguagem entender assim ou não.

Na realidade não. Os métodos de list tem implementações optionais, logo uma umodifiableList sim substitui um list.

quanto ao buffer ele é um InputStream sim, o que o torna um decorator. Ele É-UM InputStream e ele é composto por um InputStream. Ser X e ter um X é a condição sin qua non para ser um decorator. A outra é ter funcionaliade extra. e funcionalidade significa métodos extra e não implementação diferente ( isso é um proxy). BufferInputStream não fecha este requisito, o que o torna um proxy e não um decorator. como disse, a diferença é subtil. Mas por exemplo ByteArrayOutputStream é claramente um decorator de OutputStream já que ele tem o método toByteArray() que não existe em OutputStream.

Decorator => existe composição de um objeto do tipo X em um objeto da hierarquia de X + métodos adicionais.
O decorator sempre pode substituir o decorado

Proxy => existe composição de um objeto do tipo X em um objeto da hierarquia de X + implementação diferente
O proxy sempre pode substituir o "proxizado"

Não. Tem que haver novos métodos, caso contrário é um proxy. A menos que vc ache que proxy e decorator são nomes para o mesmo padrão. (eu não acho)

ViniGodoy

Ok, Sergio. Pode apenas me citar no livro do GoF, onde diz que o decorator precisa ter novos métodos para não ser um proxy?
Estou com ele aberto aqui e não achei.

Eu entendo por funcionalidade extra não a presença de métodos, mas o serviço que a classe presta. O BufferedInputStream agrega um buffer, logo, ele tem uma funcionalidade extra. Ele também tem um objeto agregado. Além disso, o papel dele não é controlar acesso, e sim acrescentar essa funcionalidade. Portanto, um decorator. Aliás, o próprio exemplo do livro do GoF envolve streams, e ele nem sequer dá a entender que métodos extras são necessários.

A diferença entre o decorator e o proxy está na motivação.
O proxy necessariamente representa um outro objeto, e geralmente tem o papel de controlar o acesso. Ele geralmente vai se comportar exatamente como o objeto representado, quando ele julgar que deve responder por aquele objeto.

O decorator tem o papel de acrescentar funcionalidade.

A presença ou não de métodos adicionais não é obrigatória em nenhum dos casos.

Abdon

Sergio vc esta confundindo herança com encapsulamento, já que vc citou a wilkpedia, vou usar a mesma fonte.

Isso citado acima é implementar uma interface não tem haver com a definição de herança.

Quando se implementa uma interface, não existe generalização, não se aproveita comportamento, e muito menos as propriedades, já que nem se define propriedades em uma interface.

Agora quanto da definição de Decorator e Proxy eu prefiro nem entrar no merito, pois para mim, o importante do padrão é o problema que ele resolve, de forma extensível e reutilizavel. Diferenças de implementação sempre irão surgir de acordo com o caso\linguagem de programação utilizada.

Abdon

Nessa eu não entendi traits são decorators por design?

Vc poderia me explicar prq um trait é um decorator por design?

sergiotaborda

ViniGodoy:
Ok, Sergio. Pode apenas me citar no livro do GoF, onde diz que o decorator precisa ter novos métodos para não ser um proxy?
Estou com ele aberto aqui e não achei.

E não vai achar mesmo. O GoF não é o unico catalogo de padrões do mundo.
Se fosse, o padrão Proxy não existiria pois não consta desse catálogo.

Como eu disse antes, se vc considerar que Decorator não envolve métodos a mais, então Decorator é a mesma coisa que Proxy. sem distinção. São dois nomes para a mesma coisa. Isso não faz muito sentido quando a mim.
Como eu tb já disse, eu não considero que sejam a mesma coisa, e portanto, quanto a mim sim existe uma distinção. E não sou o único.

http://powerdream5.wordpress.com/2007/11/17/the-differences-between-decorator-pattern-and-proxy-pattern/

“Adding functions”, não “adding functionality”. (veja no diagrama que existe um método a mais chamado Adicionalbehavior)

Porque ele não distinguem entre Decorator, Wrapper e Proxy. tudo bem se vc for por esse caminho, mas vc tem que explicitamente dizer isso, pois existe outra corrente dizendo que existem diferenças.


O decorator tem o papel de acrescentar funcionalidade.

A presença ou não de métodos adicionais não é obrigatória em nenhum dos casos.

O decorator tem a missão de adicional funções ( aka método) , não funcionalidade. Funcionalidade todos os padrões de encapsulamento acrescentam. (function, não “functionality”)

Veja os diagramas sobre o decorator, sempre vc vai ver um método a mais que não existe na classe decorada. É esse método que é o objetivo do padrão. Acho que o site acima deixa clara a diferença, basta olhar os diagramas.

sergiotaborda

ovelha:
sergiotaborda:

Em scala, por exemplo, vc tem traits que não são nem interfaces nem classes, são um conceito diferente. E eles são decorators por design.

Nessa eu não entendi traits são decorators por design?

Traits existem para adicionar funcões a classes que não as têm,mas eles têm que ser amarrados à classe logo, eles são decoradores dessa classe.

http://www.evolutionnext.com/blog/entry/title/Decorator+Pattern+In+Scala.html

Criado 11 de janeiro de 2010
Ultima resposta 13 de jan. de 2010
Respostas 16
Participantes 5