Vamos continuar nossa série de publicações sobre Design Patterns e PHP. É claro, que eu quero passar nesta série apenas uma visão geral de como padrões de projeto podem melhorar a maneira que você desenvolve, principalmente para aqueles que não conhecem MVC ou não costumam utilizar OO em seus códigos.

Se você está desenvolvendo em PHP de forma estruturada, acredito que esteja na hora de você começar a rever seus conceitos de desenvolvimento; Para isto estou criando esta série, tanto para aqueles que nunca levaram POO a sério, como para aqueles que já desenvolvem desta maneira.

Padrões melhoram seus códigos, sua manutenção, visão geral do programa, entre muitas outras vantagens que já foram citadas na publicação anterior, a qual eu recomendo que você leia.

Vamos abordar nesta publicação alguns conceitos básicos de sobre Factory.

Revisando

Anteriormente eu tentei passar uma visão geral, do que são padrões de projetos, quais as vantagens de utilizar padrões e apresentei uma classe simples contendo um singleton.

O que é um singleton e qual o seu uso?

Singleton, é um padrão de projeto de software (do inglês Design Pattern). Este padrão garante a existência de apenas uma instância de uma classe, mantendo um ponto global de acesso ao seu objeto. (Fonte: Wikipédia – http://pt.wikipedia.org/wiki/Singleton)

Com isto em mente, vamos continuar nosso estudo sobre Design Patterns e implementar um pouco mais o código da publicação anterior.

Abrindo uma fábrica

O conceito de fábrica (Factory) de acordo com Kevin McArthur, nos diz que “Fábricas são quaisquer classes que contenham um método cujo principal propósito é criar outro objeto.” Dessa forma, podemos ver o conceito de Factory como um dos métodos mais importantes para a utilização de polimorfismo.

Nada melhor que analisar um código ou colocar a teoria em prática.

<?php
// animal.php
class Animal {
	public static function factory($type) {
		require_once $type.'.php';
		return new $type;
	}
}
<?php
// horse.php
class Horse {
	public function __construct() {
		echo "<p>I'm a horse!</p>";
	}
}
<?php
// monkey.php
class Monkey {
	public function __construct() {
		echo "<p>I'm a monkey!</p>";
	}
}

Agora nós temos três classes, sendo que a classe Animal é a nossa fábrica, e através dela instanciaremos as demais classes. Claro que este é um exemplo bem grotesco, mas isto facilita a visualização, pois temos um código simples e limpo. Vamos continuar, agora vamos utilizar nossa fábrica, e ver como ela funciona.

Chamamos nosso método de factory, por convenção, não existe no PHP um método pré-definido para isto; desta forma poderia ser qualquer outro nome, mas vamos seguir as boas práticas e fazer da forma correta.

<?php
require_once 'animal.php';
$horse = Animal::factory('Horse');
$monkey = Animal::factory('Monkey');

Muito bem, se tudo ocorreu como o planejado, você deverá ter duas mensagens, informando que as classes foram instanciadas corretamente através da nossa fábrica.

Como nosso código funcionou? Bom, é bastante simples, se você conseguiu ler o código acima adequadamente, você deve perceber que a nossa classe Animal é a nossa fábrica, que possuí um método publico estático chamado factory, que por sua vez recebe um parâmetro que informa a nossa fábrica qual objeto ela deve criar e retornar.

Exemplo: Fábrica de imagem

Agora que tal criarmos um exemplo mais aplicável? Vou usar o exemplo do livro do Kevin McArthur, Pro PHP Patterns, Frameworks, Testing and More; Alias, eu recomendo imensamente este livro para aqueles que desejam aperfeiçoar seus conhecimentos em PHP.

Colocando nosso raciocínio em linha, nós queremos criar uma fábrica que seja capaz de instanciar objetos que nos permitirão trabalhar com imagens do tipo Image_JPEG e Image_PNG; Cada tipo de imagem por sua vez possuem características similares como altura, largura e conteúdo. Com essas informações em mãos vamos coloca-las na massa, digo, no código.

<?php
// IImage.php
interface IImage {
	function getHeight();
	function getWidth();
}
<?php
// Image_PNG.php
@require_once 'IImage.php';
class Image_PNG implements IImage {
	private $_width, $_height, $_file;

	public function __construct($file) {
		$this->_file = $file;
		$this->_parse();
	}

	private function _parse() {
		list($this->_width, $this->_height) = getimagesize($this->_file);
	}

	public function getWidth() {
		return $this->_width;
	}

	public function getHeight() {
		return $this->_height;
	}
}
<?php
// Image_JPEG.php
class Image_JPEG implements IImage {
	private $_width, $_height, $_file;

	public function __construct($file) {
		$this->_file = $file;
		$this->_parse();
	}

	private function _parse() {
		list($this->_width, $this->_height) = getimagesize($this->_file);
	}

	public function getWidth() {
		return $this->_width;
	}

	public function getHeight() {
		return $this->_height;
	}
}
<?php
// ImageFactory.php
class ImageFactory {
	public static function factory($file) {
		$pathParts = pathinfo($file);
		switch(strtolower($pathParts['extension'])) {
			case 'jpg':
				@require_once "Image_JPEG.php";
				$ret = new Image_JPEG($file);
				break;
			case 'png':
				@require_once "Image_PNG.php";
				$ret = new Image_PNG($file);
				break;
			default:
				throw new Exception("File format is not supported!");
		}
		if($ret instanceof IImage) {
			return $ret;
		} else {
			throw new Exception("An unknown error has occurred!");
		}
	}
}

Este exemplo deu um pouco de trabalho, não? Eu acredito que essa não seja a melhor forma de abstrair os dados, mas como eu propus utilizar um exemplo do livro, aqui estamos nós, eu modifiquei apenas algumas pequenas linhas, e implementei algumas coisas que faltavam no exemplo.

Agora vamos ver como essa nossa fábrica funcionará na prática.

<?php
$file = 'http://blog.luders.com.br/wp-content/themes/wp001/images/logo.png';
$image = ImageFactory::factory($file);
echo 'Width: '.$image->getWidth().' Height: '.$image->getHeight();
if($image instanceof Image_PNG) {
	echo ' - Image format is PNG';
}
if($image instanceof Image_JPEG) {
	echo ' - Image format is JPEG';
}

E assim terminamos nosso estudo sobre o padrão de projetos Factory. Espero que todos tenham entendido, e apreendido com este artigo; Dúvidas, sugestões, correções, observações e críticas construtivas são e sempre serão bem vindas, por este motivo os comentários estão abertos.

Design Patterns com PHP – Factory
Tamanho: 3Kb
Formato: Zip

Até nosso próximo artigo, onde falarei sobre alguns outros conceitos que fazem parte de padrões de projetos, como padrões estruturais e comportamentais, e como utiliza-los dentro de projetos PHP.