Padrão Abstract Factory

Olá a todos,
Já existem vários tópicos sobre esse padrão de projeto, eu sei, mas minha dúvida é um pouco mais específica.
Bom, primeiro vai o código.
Tenho assim o meu Abstract Factory:

public abstract class UsuarioFactory {
	
	public abstract Usuario create();
	
	public static UsuarioFactory getInstance(Class<?> tipoUsuario){
		if(tipoUsuario.getSimpleName().equals(UsuarioFisico.class.getSimpleName()))
			return new UsuarioFisicoFactory();
		else if(tipoUsuario.getSimpleName().equals(UsuarioJuridico.class.getSimpleName()))
			return new UsuarioJuridicoFactory();
		else
			return null;
	}
}
public class UsuarioFisicoFactory extends UsuarioFactory {
	UsuarioFisicoFactory() {
		
	}

	@Override
	public Usuario create() {
		return new UsuarioFisico();
	}
}
public class UsuarioJuridicoFactory extends UsuarioFactory {
	UsuarioJuridicoFactory() {
		
	}
	
	@Override
	public Usuario create() {
		return new UsuarioJuridico();
	}
}

Bom, primeiro, como existem aqui vários experts no assunto, gostaria de saber se consegui assimilar o padrão, segundo, e principal, diz respeito a utilizaçao por parte do cliente:

UsuarioFactory objUsuarioFactory;
			Usuario objUsuario;
			String tipoPessoa = input.getString("tipo_pessoa");
			
			//Usuario Físico
			if(tipoPessoa.equals("1")){
				objUsuarioFactory = UsuarioFactory.getInstance(UsuarioFisico.class);
				objUsuario = (UsuarioFisico)objUsuarioFactory.create();
			} else {
				objUsuarioFactory = UsuarioFactory.getInstance(UsuarioJuridico.class);
				objUsuario = (UsuarioJuridico)objUsuarioFactory.create();
			}
			objUsuario.setSenha(Cryptographer.getMD5(objUsuario.getSenha()));

É correto o método “create()” retornar a classe abstrata (Usuario)? Acho estranho, pois, assim teria que fazer um cast toda hora, até pq UsuarioFisico tem o método getCpf(), no qual não existe, obviamente no UsuarioJuridico…
Opinem, por favor…

Obrigado!

É assim mesmo, a aplicação não deve saber qual o tipo de factory usada ou objeto retornado. O que importa é que o ‘tipo certo’ seja retornado.

Bom, neste caso você vai ter que fazer cast. Pois o método getCpf não existe em UsuarioJuridico. Mas veja que fica mais interessante quando você tem métodos sobrescritos, e em tempo de execução, é decidido qual executar.

[quote=spinow]Olá a todos,
Já existem vários tópicos sobre esse padrão de projeto, eu sei, mas minha dúvida é um pouco mais específica.
Bom, primeiro vai o código.
Tenho assim o meu Abstract Factory:

public abstract class UsuarioFactory {
	
	public abstract Usuario create();
	
	public static UsuarioFactory getInstance(Class<?> tipoUsuario){
		if(tipoUsuario.getSimpleName().equals(UsuarioFisico.class.getSimpleName()))
			return new UsuarioFisicoFactory();
		else if(tipoUsuario.getSimpleName().equals(UsuarioJuridico.class.getSimpleName()))
			return new UsuarioJuridicoFactory();
		else
			return null;
	}
}
public class UsuarioFisicoFactory extends UsuarioFactory {
	UsuarioFisicoFactory() {
		
	}

	@Override
	public Usuario create() {
		return new UsuarioFisico();
	}
}
public class UsuarioJuridicoFactory extends UsuarioFactory {
	UsuarioJuridicoFactory() {
		
	}
	
	@Override
	public Usuario create() {
		return new UsuarioJuridico();
	}
}

Bom, primeiro, como existem aqui vários experts no assunto, gostaria de saber se consegui assimilar o padrão, segundo, e principal, diz respeito a utilizaçao por parte do cliente:

UsuarioFactory objUsuarioFactory;
			Usuario objUsuario;
			String tipoPessoa = input.getString("tipo_pessoa");
			
			//Usuario Físico
			if(tipoPessoa.equals("1")){
				objUsuarioFactory = UsuarioFactory.getInstance(UsuarioFisico.class);
				objUsuario = (UsuarioFisico)objUsuarioFactory.create();
			} else {
				objUsuarioFactory = UsuarioFactory.getInstance(UsuarioJuridico.class);
				objUsuario = (UsuarioJuridico)objUsuarioFactory.create();
			}
			objUsuario.setSenha(Cryptographer.getMD5(objUsuario.getSenha()));

É correto o método “create()” retornar a classe abstrata (Usuario)? Acho estranho, pois, assim teria que fazer um cast toda hora, até pq UsuarioFisico tem o método getCpf(), no qual não existe, obviamente no UsuarioJuridico…
Opinem, por favor…

Obrigado!

[/quote]

Está quase lá… o seu método getInstance() está meio “complicado”, porque se o cliente sabe que Usuário quer, como nessa linha:

objUsuarioFactory = UsuarioFactory.getInstance(UsuarioJuridico.class);

então não tem porque usar factory, concorda?
Nesse caso (especificamente), eu diria a você criar um mapa com o input e atrelar às instâncias de factory que você quer. Por exemplo:


static Map<String, UsuarioFactory> map;

static {
 map = new HashMap<String, UsuarioFactory>();
 map.put ("1", new UsuarioFisicoFactory());
 map.put ("2", new UsuarioJuridicoFactory()); 
}


public UsuarioFactory getFactory(String input) {
    //Estou com preguiça de digitar getter e setter pro map =P
    return map.get(input);
}

Assim, você anexa o input de acordo com a Factory, mas se ficar tudo na mesma classe, não tem problema.
Quanto ao caso do método getCpf, você poderia fazer um esquema semelhante de classes abstratas, mas com os usuários. Substitua getCpf() por getDocumento, que fica numa interface (evite usar herança!) e substitua o método na sua classe Factory, tb.

[]´s

Tem toda a razão… realmente fugiu da idéia da utilização do padrão…

Curti a idéia de passar o input, massa mesmo!

Ótima alternativa tbm!

Valew pela ajuda de todos!

Eu prefiro algo do tipo:

 public abstract class UsuarioFactory {  
       
     public static UsuarioFactory getUsuarioFisicoFactory(){  
             return new UsuarioFisicoFactory();  
     }  
     
     public static UsuarioFactory getUsuarioJuridicoFactory(){  
             return new UsuarioJuridicoFactory();  
     }
 } 

Assim não precisa saber as flags, os nomes dos métodos já deixam claro o que será retornado.

[quote=mario.fts]Eu prefiro algo do tipo:

 public abstract class UsuarioFactory {  
       
     public static UsuarioFactory getUsuarioFisicoFactory(){  
             return new UsuarioFisicoFactory();  
     }  
     
     public static UsuarioFactory getUsuarioJuridicoFactory(){  
             return new UsuarioJuridicoFactory();  
     }
 } 

Assim não precisa saber as flags, os nomes dos métodos já deixam claro o que será retornado.[/quote]

Pode até ser. Mas aí deixaria de ser um Abstract Factory, que é um padrão que abstrai uma família de factories. Afinal, na sua implementação, o cliente sabe qual factory está sendo utilizado, o que não é a intenção.

e passando o flag ele não sabe?

Naquele jeito que eu passei alí em cima, não. Ele só sabe que , de acordo com o input, ele vai retornar uma factory diferente. Acontece que esse input vem do controller, que vem da view… ou seja, vai mudando. Se por acaso a view acrescentar mais valores, por exemplo, é só acrescentar uma entrada no map.

[]´s

Se eu consegui entender a necessidade do padrão Abstract Factory, acredito que esta explicação é bem válida, pois, deixa mais “genérico”. Certo?

[quote=spinow][quote]
Naquele jeito que eu passei alí em cima, não. Ele só sabe que , de acordo com o input, ele vai retornar uma factory diferente. Acontece que esse input vem do controller, que vem da view… ou seja, vai mudando. Se por acaso a view acrescentar mais valores, por exemplo, é só acrescentar uma entrada no map.
[/quote]

Se eu consegui entender a necessidade do padrão Abstract Factory, acredito que esta explicação é bem válida, pois, deixa mais “genérico”. Certo?[/quote]

Certo! Você está deixando de lado a necessidade de saber qual o produto. OK, você está acoplando a entrada com uma factory, mas como eu disse antes, não tem problema se você fizer isso num façade ou coisa assim.

[]´s