Article Image
Article Image
read

Voltando com os posts, vou começar uma série falando sobre os padrões de projeto do livro Design Patterns do GoF(Gang of Four).

Mas primeiro, o que é esse troço de Design Patterns? “Kibando” o próprio livro do GoF:

Os padrões de projeto tornam mais fácil reutilizar projetos e arquiteturas bem-sucedidas. Expressam técnicas testadas e aprovadas … ajudam a escolher alternativas de projeto que tornam um sistema reutilizável e a evitar alternativas que comprometam a reutilização…

Sacou?

NEEEEXT!

Abstract Factory

A idéia do pattern Abstract Factory é fornecer uma interface para criação de famílias de objetos relacionados ou mesmo dependentes, porém sem especificar suas classes completas.

O exemplo mais clássico é uma interface para usuário, na qual conforme uma configuração de sistema ou whatever, a construção das janelas é feita de uma forma diferente, cores, tamanho, etc.

Aplicabilidade:

  • um sistema deve ser independente de como seus “produtos” são criados, compostos ou representados;
  • um sistema deve ser configurado como um “produto” de uma família de múltiplos “produtos”;
  • uma família de “objetos-produto” for projetada para ser usada em conjunto, e você necessita garantir esta restrição;
  • você quer fornecer uma biblioteca de classes de “produtos” e quer revelar somente suas interfaces, não suas implementações.
(kibado da versão em pt-br, por isso tá estranho)

Mais do que ficar explicando, vamos para o que importa.Mas como eu gosto de exemplos diferentes, vou fazer um bem bizarro. :P

Pokémon, temos que pegar…

Tenho este pokémon, Eevee, vou querer evoluí-lo. E como eu sou um grande mestre-pokémon ele já está para evoluir. E as evoluções naturais dele são Espeon e Umbreon (peguei as informações aqui). Porém ele tem restrições, quando ele estiver no ponto de evoluir, se for dia, evoluir para Espeon, se for noite para Umbreon.

Antes de tudo vou precisar do meu Pokémon

1
2
3
4
5
6
7
8
9
10
11
public class Pokemon {
	private String nome;

	public String getNome() {
		return nome;
	}

	public void setNome(String nome) {
		this.nome = nome;
	}
}

E agora precisamos criar uma classe abstrata declarando uma interface genérica para criação das subclasses que fabricam as evoluções do Eevee.

1
2
3
4
5
6
abstract class FabricaDeEvolucoesDoEevee {
	public static void obterFabrica() {
	}

	public abstract Pokemon criarEvolucao();
}

Mas essa classe precisa retornar uma fabrica de evoluções conforme a regra de evolução acima. Então precisamos alterar  FabricaDeEvolucoesDoEevee e criar as fabricas de cada evolução. Fazemos uma verificação se esta entre  o periodo do dia pra retornar uma fabrica de Espeon, caso não esteja retorna uma fabrica de Umbreon.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import java.util.Calendar;

abstract class FabricaDeEvolucoesDoEevee {
	private static Calendar manha;
	private static Calendar tarde;

	static {
		manha = Calendar.getInstance();
		manha.set(Calendar.HOUR_OF_DAY, 6);
		manha.set(Calendar.MINUTE, 0);
		manha.set(Calendar.SECOND, 0);

		tarde = Calendar.getInstance();
		tarde.set(Calendar.HOUR_OF_DAY, 18);
		tarde.set(Calendar.MINUTE, 0);
		tarde.set(Calendar.SECOND, 0);
	}

	public static FabricaDeEvolucoesDoEevee obterFabrica() {
		Calendar dataDaEvolucao = Calendar.getInstance();
		if (dataDaEvolucao.after(manha) && dataDaEvolucao.before(tarde)) {
			return new FabricaDeEspeon();
		}
		return new FabricaDeUmbreon();
	}

	public abstract Pokemon criarEvolucao();
}

A fabrica de Espeon herdando da classe abstrata.

1
2
3
4
5
6
7
8
public class FabricaDeEspeon extends FabricaDeEvolucoesDoEevee {
	@Override
	public Pokemon criarEvolucao() {
		Pokemon espeon = new Pokemon();
		espeon.setNome("Espeon");
		return espeon;
	}
}

A fabrica de Umbreon herdando da classe abstrata.

1
2
3
4
5
6
7
8
public class FabricaDeUmbreon extends FabricaDeEvolucoesDoEevee {
	@Override
	public Pokemon criarEvolucao() {
		Pokemon umbreon = new Pokemon();
		umbreon.setNome("Umbreon");
		return umbreon;
	}
}

Agora vamos fazer uma classe main para testar esse código.

1
2
3
4
5
6
7
public class AbstractFactoryMain {
	public static void main(String[] args) {
		FabricaDeEvolucoesDoEevee fabrica = FabricaDeEvolucoesDoEevee.obterFabrica();
		Pokemon pokemon = fabrica.criarEvolucao();
		System.out.println("Evoluiu para " + pokemon.getNome() + "!");
	}
}

Devemos ver no console “Evolui para Espeon!” se estiver rodando o código da AbstractFactoryMain entre as 6hrs e 18hrs, e ver “Evolui para Umbreon!” se for entre 18hrs e 6hrs.

Se olhar esse link poderiamos criar novas factorys para cada evolução, mas teria que definir qual critério para simular as pedras de evolução, ai poderia ser alguma configuração ou whatever.

Esse pattern é bem simples, não?

[UPDATE]

Depois do @diegoponci ficar me trollando no GTalk falando que “tinha que retornar o tipo específico…#mimimi” as classes foram alteradas e ficaram assim:

Criei duas classes específicas de cada tipo;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class Umbreon extends Pokemon {
	private String nome = "Umbreon";

	@Override
	String getNome() {
		return this.nome;
	}
}

public class Espeon extends Pokemon {
	private String nome = "Espeon";

	@Override
	String getNome() {
		return this.nome;
	}
}

Assim transformando a classe Pokemon com apenas um método abstract;

1
2
3
abstract class Pokemon {
	abstract String getNome();
}

E alterei as Factories de cada tipo;

1
2
3
4
5
6
7
8
9
10
11
12
public class FabricaDeUmbreon extends FabricaDeEvolucoesDoEevee {
	@Override
	public Umbreon criarEvolucao() {
		return new Umbreon();
	}
}
public class FabricaDeEspeon extends FabricaDeEvolucoesDoEevee {
	@Override
	public Espeon criarEvolucao() {
		return new Espeon();
	}
}
Blog Logo

Marcelo Tozzi


Published

Image

Marcelo Tozzi

Mais um blog de desenvolvedor

Back to Overview