Bom dia, gostaria de saber se no java é possivel sobreescrever metodos de iinstancias de objetos ja existentes.
Por exemplo, na hora da criação de um produto eu posso alterar o método toString:
Produto prod = new Produto(){
@Override
public String toString() {
return getProda60descr()+" xxx";
}
};
Porém vamos supor que eu tivesse um produto ja existente, recuperado do banco de dados usando o hibernate:
Olá Mateus! Acho que não é possível, porém, veio uma idéia meio doida na minha cabeça… Se você fizer a classe Produto receber um Produto em seu construtor talvez de certo… entende? Caso não funcione favor desconsiderar completamente o que disse (não cheguei a testar) :roll:
public class Produto {
private Produto produto;
public Produto() {
// TODO Auto-generated constructor stub
}
public Produto(Produto produto) {
// TODO Auto-generated constructor stub
this.produto = produto;
}
public Produto getProduto(){
return produto;
}
}
public class Main {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
Produto p = new Produto();
Produto produto = new Produto(p){
@Override
public String toString(){
return "Olá";
}
};
System.out.println(produto);
System.out.println(produto.getProduto());
}
}
Pq vc nao cria um construtor com uma passagem de parametro do valor do retorno do toString(), ai no toString() vc retorna esse atributo passado por parametro no construtor
edit:
Exemplo:
public class Produto {
private String retornoString;
public Produto(String retornoString) {
this.retornoString = retornoString;
}
public String toString() {
return getProda60descr()+ retornoString;
}
}
//na chamada
Produto p = new Produto("Olá");
System.out.println(p);
[quote=igor_ks]Pq vc nao cria um construtor com uma passagem de parametro do valor do retorno do toString(), ai no toString() vc retorna esse atributo passado por parametro no construtor
edit:
Exemplo:
[code]
public class Produto {
private String retornoString;
public Produto(String retornoString) {
this.retornoString = retornoString;
}
public String toString() {
return getProda60descr()+ retornoString;
}
}
//na chamada
Produto p = new Produto(“Olá”);
System.out.println§;
[/code][/quote]
Bem melhor!
Se bem que como ele não poderá instanciar um novo objeto, acho que teria que ser por algum metódo setXXX ao invés do contrutor :?:
Veja que você não está alterando o método toString na criação de um produto! Você está criando uma classe anônima, e sobrescrevendo o método, se você quer esse tipo de comportamento deve pesquisar sobre “Instrumentação”.
Um exemplo de coisa que as pessoas perguntam muito é como mudar o comportamento de um objeto já existente. Normalmente você delega esse comportamento a outras classes, que são associadas (via operação TEM UM , não É UM) ao objeto em questão.
Vamos dar um exemplo: digamos que você tenha criado um jogo em que um personagem começa como bebê, depois passa a aprendiz, depois a soldado, então a guerreiro ou mago, e assim por diante.
A primeira idéia é que o objeto seja criado com uma classe que não tem habilidade nenhuma, e você vá adaptando o comportamento desse objeto à medida que ele for promovido (ou seja, ganhando novas habilidades.
Como você não pode mudar a classe de objeto em tempo de execução, uma maneira de você fazer isso é definir habilidades, e ir associando as habilidades à medida que o objeto (o personagem) for sendo promovido. Então, em vez de você dizer que “Objeto Gandalf faz mágica”, você diz que “Objeto Gandalf tem a habilidade de fazer mágica”, e chama o método “fazer mágica” da habilidade “Ser mágico”.
[quote=mateusviccari]Bom dia, gostaria de saber se no java é possivel sobreescrever metodos de iinstancias de objetos ja existentes.
Por exemplo, na hora da criação de um produto eu posso alterar o método toString:
Produto prod = new Produto(){
@Override
public String toString() {
return getProda60descr()+" xxx";
}
};
Porém vamos supor que eu tivesse um produto ja existente, recuperado do banco de dados usando o hibernate:
Produto p = session.get(Produto.class, 14);
Como poderia alterar o toString desse produto?[/quote]
A solução é parecida com o que o Felipe disse. Vc precisa usar o padrão Decorator.
O padrão Decorator significa criar outra classe que herda de produto e contém um produto. Ai tem o método toString modificado. Todos os metodos delegam a sua chamada para os mesmos metodos no objeto original.
Vc pode criar um Decorador dinamincamente se usar bibliotecas de bytecode rewirte como a cglib que usa no binernate.
Tudo isto é possivel, mas é altamente não acontecelhado. Ainda por cima para mudar o toString que nem sequer é um metodo de negocio.
O que vc quer fazer denota que alguma coisa no seu modelo está errada. Pense em outra solução e nos diga exatamente que problema vc está tentando resolver.
Com o auxílio de Javassist por exemplo é possível manipular os bytecodes, veja o exemplo:
package teste;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import javassist.CannotCompileException;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.NotFoundException;
public class JavaSist {
public static void main(String[] args) throws NotFoundException, CannotCompileException, IOException, SecurityException, IllegalArgumentException, NoSuchMethodException, IllegalAccessException, InvocationTargetException {
metodo();
}
public static void metodo() throws NotFoundException, CannotCompileException, IOException, SecurityException, NoSuchMethodException, IllegalArgumentException, IllegalAccessException, InvocationTargetException{
ClassPool pool = ClassPool.getDefault();
CtClass cc = pool.get("teste.Rectangle");
cc.setSuperclass(pool.get("teste.Point"));
cc.writeFile();
Class clazz = cc.toClass();
System.out.println(new teste.Rectangle().getClass().getSuperclass());
}
}
No codigo acima foi alterada a superclasse de Rectangle, lógico que talvez não se aplique a um proposito simples como o apresentado, mais é uma alternativa se não for possível alterar o codigo fonte para adicionar comportamentos…
Primeiramente obrigado a todos que responderam… aprendi algumas coisas que nao sabia nem que era possível fazer…
O meu objetivo pra isso é meramente informativo, na verdade a duvida surgiu quando tive que criar um combobox que iria guardar varios produtos, sendo que nesse combobox não deveria ser mostrado o toString padrão do produto que retornava somente seu nome, e sim que mostrasse o nome e também a unidade de medida.
Estava pensando em fazer algo usando interfaces, funcionou e não precisei implementar quase nada, creio que pro meu caso seria o melhor jeito, algo assim:
Classe produto:
package testes;
public class Produto {
private String nome;
private StringReturn stringReturn;
public String getNome() {
return nome;
}
public void setNome(String nome) {
this.nome = nome;
}
public StringReturn getStringReturn() {
return stringReturn;
}
public void setStringReturn(StringReturn stringReturn) {
this.stringReturn = stringReturn;
}
@Override
public String toString() {
if(stringReturn==null){//retorno padrão, caso nao exista um stringReturn especifico
return nome;
}else{//retorna o método da interface
return stringReturn.getString();
}
}
}
Interface usada pra retornar uma string
package testes;
public interface StringReturn {
public String getString();
}
Um exemplo de utilização:
Produto p1 = new Produto();
p1.setNome("Abacaxi explosivo");
System.out.println(p1);
final Produto p2 = new Produto();
p2.setStringReturn(new StringReturn() {
@Override
public String getString() {
return "Esse eh o retorno personalizado do produto "+p2.getNome();
}
});
p2.setNome("Laranja mecânica");
System.out.println(p2);
p2.setNome("Laranja elétrica");
System.out.println(p2);
Poderia tambem ao invés de usar interface, usar classe abstrata e fazer o método construtor dela receber um objeto, ai não precisaria declarar as variaveis como final.
[quote=mateusviccari]Primeiramente obrigado a todos que responderam… aprendi algumas coisas que nao sabia nem que era possível fazer…
O meu objetivo pra isso é meramente informativo, na verdade a duvida surgiu quando tive que criar um combobox que iria guardar vários produtos, sendo que nesse combobox não deveria ser mostrado o toString padrão do produto que retornava somente seu nome, e sim que mostrasse o nome e também a unidade de medida.
[/quote]
Mas tudo se resume ao padrão Decorator que falei antes. Esse é o jeito padrão e esperado por outros programadores.
Um outro conceito que é util , sobretudo em swing é o conceito de View Object. O View Object é um objeto que só a view usa. É o objeto que vc manda para o swing. Este objeto não é o mesmo que vem do banco. Normalmente ele tem mais ou menos propriedades que o do banco. E é muito util para juntar inforações que no banco estão em lugares diferentes. É um padrão util em web também.
Eis como seria um View Object padrão para usar em combos
public class ComboItem {
private String text;
private Object id;
public ComboItem (Object id , String text) {
this.id = id;
this.text = text;
}
// gets e sets
}
// uso
List<Produto> produtos = ...
List<ComboItem> listaParaCombo = new ArrayList<ComboItem>(produtos.size());
for (Produto p : produtos ){
listaParaCombo.add( new ComboItem(produto.getId(), produto.getNome() + " (" + produto.getUnidade() + ")");
}
//agora é só usar o listaParaCombo no combo. Prefrivelmente em uma implementação de ComboModel.
Este tipo de padrão ajuda a deixar o codigo da view a ficar desacoplado do codigo do resto do sistema e as entidades não precisa se preocupar em como são ser mostradas na tela. Isso não é responsabilidade delas.