Abstract Factory vs Factory Method

Para melhor compreensão nos estudos de Abstract Factory e de Factory Method, foi feito uma tabela que identifica as diferenças entre dois.

Abstract Factory Factory Method
1. usa os objectos usa as classes
2. cria objectos através de composição cria objectos através de herança
3. fornece um tipo abstracto para criar uma família de produtos. Ao criar subclasses dum tipo de produto, define como estes produtos são produzidos. Tal como Factory Method, mantém clientes descolados dos tipos concretos. Os clientes só precisam de saber o tipo abstracto que eles estão usar e a subclasse preocupa com os tipos concretos. Mantém os clientes descolados dos tipos concretos
4. Agrupa um conjunto de produtos relacionados Só cria um produto, não uma família de produtos.
5. Tem interface grande (não é a keyword mas sim o código) por causa disto é usado para criar famílias de produtos inteiras. Não tem uma interface grande porque tudo o que é necessário é só um método!
6. usa Factory Method para criar productos.

La Princesa Iberica

Nesta pequena intervenção de trabalho, fui responsável pela transferência de alojamento dum site WordPress da empresa espanhola La Princesa Iberica. A empresa espanhola sentiu necessidade de mudar o alojamento pelas suas razões e não foi possível de fornecer as passwords do mesmo.

Foi necessário estudar as classes da WordPress, criar um pequeno ficheiro PHP e escrever o seguinte código:

$hash_cost_log2 = 8;
$hash_portable = FALSE;
$pass = "mypassword";

$hasher = new PasswordHash($hash_cost_log2, $hash_portable);
$hash = $hasher->HashPassword($pass);

echo "Password:" .$hash;

A password era impressa para o monitor e através da base de dados, alterou-se a password aos vários utilizadores para poder gerir os conteúdos do site.

Command Pattern

Command – encapsulates a request as an object, thereby letting you parameterize other objects with different requests, queue or log requests, and support undoable operations – Page 206, Chapter 6, Head First Design Patterns

Em português, a Command Pattern encapsula um pedido como um objecto, assim deixa – nos definir os parâmetros dos outros objectos com diferentes tipos de pedido e suporta operações revertíveis.

Command Pattern
Command Pattern

Analisando o diagrama de classes da Command Pattern, considere as seguintes exposições:

  • Command: declara uma interface para a execução duma operação;
  • ConcreteCommand: define a ligação entre objecto Receiver e uma acção. Implementa o método Execute pela invocação da operação correspondente no Receiver;
  • Client: cria um objecto ConcreteCommand e estabelece o seu Receiver;
  • Invoker: pede o comando para executar o pedido;
  • Receiver: sabe como deve executar as operações associadas com a realização dum pedido.

Amostra de código da classe “Command”

public interface Command {
	public void execute();
}

Amostra de código da classe “ConcreteCommand”

public class LightOnCommand implements Command {
	Light light;

	public LightOnCommand(Light light) {
		this.light = light;
	}

	public void execute() {
		light.on();
	}
}

Amostra de código da classe “Client”

public class RemoteLoader {
 
	public static void main(String[] args) {
		RemoteControl remoteControl = new RemoteControl();
		
		Light livingRoomLight = new Light("Living Room");
		
		LightOnCommand livingRoomLightOn = new LightOnCommand(livingRoomLight);
		LightOffCommand livingRoomLightOff = new LightOffCommand(livingRoomLight);
		
		remoteControl.setCommand(0, livingRoomLightOn, livingRoomLightOff);
		
		System.out.println(remoteControl);
		
		remoteControl.onButtonWasPushed(0);
		remoteControl.offButtonWasPushed(0);
	}
}

Amostra de código da classe “Invoker”

public class RemoteControl {
	Command[] onCommands;
	Command[] offCommands;
 
	public RemoteControl() {
		onCommands = new Command[7];
		offCommands = new Command[7];
 
		Command noCommand = new NoCommand();
		for (int i = 0; i < 7; i++) {
			onCommands[i] = noCommand;
			offCommands[i] = noCommand;
		}
	}
  
	public void setCommand(int slot, Command onCommand, Command offCommand) {
		onCommands[slot] = onCommand;
		offCommands[slot] = offCommand;
	}
 
	public void onButtonWasPushed(int slot) {
		onCommands[slot].execute();
	}
 
	public void offButtonWasPushed(int slot) {
		offCommands[slot].execute();
	}
  
	public String toString() {
		StringBuffer stringBuff = new StringBuffer();
		stringBuff.append("\n------ Remote Control -------\n");
		for (int i = 0; i < onCommands.length; i++) {
			stringBuff.append("[slot " + i + "] " + onCommands[i].getClass().getName()
				+ "    " + offCommands[i].getClass().getName() + "\n");
		}
		return stringBuff.toString();
	}
}

Amostra de código da classe “Receiver”

public class Light {
	String location = "";

	public Light(String location) {
		this.location = location;
	}

	public void on() {
		System.out.println(location + " light is on");
	}

	public void off() {
		System.out.println(location + " light is off");
	}
}

Quando se deve usar Command Pattern?

  1. quando se pretende parametrizar os objectos por uma acção a executar;
  2. quando se especifica e executa pedidos nas alturas diferentes;
  3. quando se pretende desfazer os pedidos efectuados;
  4. quando se pretende registar as mudanças para que possam ser replicados num caso duma falha de sistema.

As conclusões que eu retiro deste estudo são:

  • separa o objecto que invoca a operação dum objecto que sabe como executar a mesma;
  • as classes Command podem ser manipuladas e extendidas como outros objectos quaisquer;
  • é fácil de adicionar novos Command porque não será preciso de efectuar as alterações nas classes existentes.