Mais conteúdo relacionado Semelhante a Design Patterns com PHP (20) Design Patterns com PHP1. Design Patterns com PHP
Conceitos, exemplos, e outras coisas
Pablo Dall'Oglio
@pablodalloglio fb/pablodalloglio
2. Adianti Solutions Ltda © Pablo Dall'Oglio Programando para Programadores #2
Meu caminho
●
Clipper (1994-1998): comercial, bibliotecas, funções;
●
Delphi (1998-1999): automação, componentes;
●
PHP (2000): SAGU (php+html+sql);
●
PHP-GTK(2001): PHP só com classes;
●
Agata Report (2001-2006);
●
Gnuteca (2002): PHP Web com classes;
●
PHP-GTK: Criando Aplicações Gráficas com PHP (2004);
●
Design Patterns (2004): Unisinos;
●
Core (2006): Primeira experiência com Framework MVC;
●
PHP: Programando com Orientação a Objetos (2007);
●
Mestrado em Engenharia de Software (2008, 2009);
●
Criando Relatórios com PHP (2011);
●
Adianti Framework para PHP (2012).
3. Adianti Solutions Ltda © Pablo Dall'Oglio Programando para Programadores #3
O que são padrões?
Existem padrões
na diversidade
Jargão próprio
4. Adianti Solutions Ltda © Pablo Dall'Oglio Programando para Programadores #4
O que são padrões?
A aplicação do padrão
depende do contexto
5. Adianti Solutions Ltda © Pablo Dall'Oglio Programando para Programadores #5
Design Pattern
O que são Design Patterns ?
“Um Pattern descreve um problema que ocorre com
frequência em nosso ambiente, e então explica a essência
da solução para este problema, de forma que tal solução
possa ser utilizada milhões de outras vezes...”
Christopher Alexander (1936 arquiteto)
Datas importantes:
●
1977 Christopher o aplica na área da Arquitetura;
●
1987 Kent Beck/Ward Cunningham programação;→
●
1994 Design Patterns: Elements of Reusable OO
Software;
●
2002 Patterns of Enterprise Application Architecture.
6. Adianti Solutions Ltda © Pablo Dall'Oglio Programando para Programadores #6
Design Patterns
●
Padrões são descobertos, não inventados;
●
Na maioria das vezes, já utilizamos algum padrão, sem
saber;
●
O conhecimento dos padrões nos leva a distinguir em
quais situações utilizá-los;
●
Não existe padrão melhor ou pior, existem padrões que
são mais indicados para determinadas situações;
●
Um padrão não é uma solução pronta;
●
Os códigos a seguir são apenas UMA das formas de
implementar os patterns, provavelmente não a melhor,
visto que aqui o enfoque é DIDÁTICO :-)
8. Adianti Solutions Ltda © Pablo Dall'Oglio Programando para Programadores #8
●
É necessário compartilhar informações (prefs, configs);
●
Visíveis dentro de diferentes contextos, classes, métodos;
●
Variáveis globais, são do mal, falta encapsulamento;
●
Como compartilhar uma única versão da verdade;
●
Singleton:
●
Classe é visível global;
●
Mas permite N Objetos;
●
E se retornasse o mesmo?
●
Limitar a instanciação;
●
Método para criar 1 Obj;
●
Não mais do que 1.
Singleton
9. Adianti Solutions Ltda © Pablo Dall'Oglio Programando para Programadores #9
●
Como fabricar apenas uma instância?
●
Seu método construtor é marcado como private;
●
Tente dar um new fora da classe terá um: Fatal Error;
●
Só poderá instanciar dentro da própria classe;
●
É preciso criar outro método de instanciação: getInstance();
●
Retornará sempre a mesma instância.
Singleton
10. Adianti Solutions Ltda © Pablo Dall'Oglio Programando para Programadores #10
<?php
class Preferencias
{
private $data;
private static $instance;
private function __construct() {
$this->data = parse_ini_file('application.ini');
}
public static function getInstance() {
if (empty(self::$instance)) {
self::$instance = new self;
}
return self::$instance;
}
public function setData($key, $value) {
$this->data[$key] = $value;
}
public function getData($key) {}
public function save() {}
}
Singleton
Única instância
que será criada
11. Adianti Solutions Ltda © Pablo Dall'Oglio Programando para Programadores #11
<?php
// obtém uma instância
$p1 = Preferencias::getInstance();
print 'A linguagem é: '. $p1->getData('language') . "<br>n";
$p1->setData('language', 'pt');
print 'A linguagem é: '. $p1->getData('language') . "<br>n";
<?php
// obtém a mesma instância
$p2 = Preferencias::getInstance();
print 'A linguagem é: '. $p2->getData('language') . "<br>n";
// Descomentar para gravar o valor
// $p1->save();
Singleton
12. Adianti Solutions Ltda © Pablo Dall'Oglio Programando para Programadores #12
Acoplamento
●
Muitos desenvolvedores integram bibliotecas assim:
Alto acoplamento: Até pode funcionar, mas...
13. Adianti Solutions Ltda © Pablo Dall'Oglio Programando para Programadores #13
●
É quanto um módulo (classe, método)
conhece e depende de outro;
●
Baixo:
– Não depende de muitas outras;
– Menos efeitos colaterais em
modificações.
●
Alto:
– Menos reutilizável sozinha;
– Mais sensível à mudanças.
●
O objetivo é criar modelos com baixo
acoplamento;
●
É impossível acoplamento ZERO;
Acoplamento
15. Adianti Solutions Ltda © Pablo Dall'Oglio Programando para Programadores #15
Facade
●
Facade ajuda a diminuir o acoplamento;
●
Oferece uma interface única para um conjunto de
interfaces de um subsistema;
●
A APP ficará dependente da Facade, não do subsistema.
APP
16. Adianti Solutions Ltda © Pablo Dall'Oglio Programando para Programadores #16
Facade
<?php
if ($paymenttype_id == 1) // PAGSEGURO
{
$paymentRequest = new PagSeguroPaymentRequest();
$item = new PagSeguroItem;
$item->setDescription( $product->description );
$item->setQuantity( $data->amount );
$item->setAmount( $price );
$paymentRequest->addItem($item);
$address = new PagSeguroAddress;
$address->setPostalCode( $customer->postal );
$address->setStreet( $customer->address );
$address->setCity( $customer->city );
$paymentRequest->setShippingAddress($address);
$sender = new PagSeguroSender;
$sender->setName( $customer->name );
$sender->setEmail( $customer->email );
$paymentRequest->setSender($sender);
}
17. Adianti Solutions Ltda © Pablo Dall'Oglio Programando para Programadores #17
Facade
<?php
else if ($paymenttype_id == 2) // PAYPAL
{
$total = ($product->price * $data->amount);
// dados para enviar para o paypal
$padata ='&CURRENCYCODE='.urlencode($ini['currency']).
'&PAYMENTACTION=Sale'.
'&ALLOWNOTE=1'.
'&PAYMENTREQUEST_0_AMT='.$total.
'&PAYMENTREQUEST_0_ITEMAMT='.$total.
'&L_PAYMENTREQUEST_0_QTY0='. $data->amount.
'&L_PAYMENTREQUEST_0_AMT0='.$product->price.
'&L_PAYMENTREQUEST_0_NAME0='.$product->description.
'&L_PAYMENTREQUEST_0_NUMBER0='.1.
'&AMT='.$total;
// obtém o token
$paypal= new PayPalFacade;
$httpresult = $paypal->PPHttpPost('SetExpressCheckout', $padata,
$ini['username'], $ini['password']);
}
?>
18. Adianti Solutions Ltda © Pablo Dall'Oglio Programando para Programadores #18
Facade
<?php
class PaymentFacade
{
public function addItem($desc, $qtde, $preco)
{
//...
}
public function setCustomer($nome, $ender, $cidade)
{
//...
}
public function setPaymentType($type)
{
//...
}
public function process()
{
//...
}
}
?>
Pode ser resolvido
com outros
padrões também
19. Adianti Solutions Ltda © Pablo Dall'Oglio Programando para Programadores #19
Adapter
●
Favorece o isolamento e a manutenção;
●
Converte a interface de uma classe em outra;
●
Também conhecido como Wrapper:
– Object Wrapper: Encapsula adaptado por composição;
– Class Wrapper: Adapta interface por herança.
20. Adianti Solutions Ltda © Pablo Dall'Oglio Programando para Programadores #20
Adapter
<?php
class PHPMailerAdapter
{
private $pm;
public function __construct()
{
$this->pm = new PHPMailer;
$this->pm-> CharSet = 'utf-8';
}
public function setFrom($from, $name)
{
$this->pm-> From = $from;
$this->pm-> FromName = $name;
}
public function setTextBody($body)
{
$this->pm-> Body = $body;
$this->pm-> IsHTML(false);
}
Wrapper por
Composição
21. Adianti Solutions Ltda © Pablo Dall'Oglio Programando para Programadores #21
Adapter
<?php
require_once 'PHPMailer.php';
require_once 'classes/PHPMailerAdapter.php';
$mail = new PHPMailerAdapter;
$mail->setUseSmtp();
$mail->setSmtpHost('smtp.gmail.com', 465);
$mail->setSmtpUser('pablo@dalloglio.net', 'minhasenha');
$mail->setFrom('pablo@dalloglio.net', 'Pablo Dall Oglio');
$mail->addAddress('destinatario@gmail.com', 'Destinatário');
$mail->setSubject('Oi Cara');
$mail->setHtmlBody('<b>Isso é um <i>teste</i></b>');
$mail->send();
22. Adianti Solutions Ltda © Pablo Dall'Oglio Programando para Programadores #22
Evolução
"... the hardest is evolving reusable object-
oriented software
We touch on this a little bit in Design Patterns.
For example, factories, adapters and facades
can help when it comes to changing and
evolving a reusable library"
Erich Gamma - Gang of Four
evoluir
24. Adianti Solutions Ltda © Pablo Dall'Oglio Programando para Programadores #24
#Go Horse 1
<?php
// configuração
$conn = pg_connect("host=localhost port=5432 dbname=exemplos...");
// query
$query = 'SELECT id, nome, endereco FROM cliente WHERE id not in (...)';
// resultados
$result = pg_query($conn, $query);
if ($result)
{
// apresentação
echo '<table border="1">';
while ($row = pg_fetch_assoc($result))
{
echo '<tr>';
echo '<td>' . $row['id'] . '</td>';
echo '<td>' . $row['nome'] . '</td>';
echo '<td>' . $row['endereco'] . '</td>';
echo '</tr>';
}
echo '</table>';
}
pg_close($conn);
Business rule?
Apresentação
Configuração
25. Adianti Solutions Ltda © Pablo Dall'Oglio Programando para Programadores #25
One script per page
●
Você começou a programar Web...
●
Cada coisa é um script;
●
Um script representa um programa;
●
Podemos ter vários scripts para o mesmo sistema;
●
Listagem a seguir:
26. Adianti Solutions Ltda © Pablo Dall'Oglio Programando para Programadores #26
Front Controller
●
Um objeto que interpreta uma requisição para uma ação e
decide o fluxo de execução a tomar;
●
Existem tarefas que se repetem por todas as rotinas (logs,
autenticação, internacionalização e padronização de interface);
●
A aplicação pode ter um ponto central de acesso, que
coordena qual programa será executado;
●
O Front Controller é um tipo de script centralizador, também
conhecido por “One script serves all”;
●
Um Front Controller geralmente é representado por um objeto
que recebe todas as requisições de um site;
●
A tarefa deste objeto é analisar alguns parâmetros, como a
URL e decidir qual comando executar, qual objeto instanciar.
28. Adianti Solutions Ltda © Pablo Dall'Oglio Programando para Programadores #28
Front Controller
index.php
<?php
if ($_GET) {
$class = $_GET['class'];
if (class_exists($class)) {
$pagina = new $class;
$pagina->show();
}
}
Page.php
class Page
{
public function show()
{
if ($_REQUEST) {
$method = $_REQUEST['method'];
if (method_exists($this, $method)) {
call_user_func(array($this, $method), $_REQUEST);
}
}
}
}
sessão, permissões, timezone,
segurança, layout...
Todos precisam ter
um método show?
Layer Supertype
29. Adianti Solutions Ltda © Pablo Dall'Oglio Programando para Programadores #29
Front Controller
<?php
class CidadeControl extends Page
{
public function listar()
{
try {
Transaction::open('livro');
$cidades = $cidade->all();
if ($cidades) {
foreach ($cidades as $cidade) {
print "{$cidade->id} - {$cidade->nome}<br>";
}
}
Transaction::close();
}
catch (Exception $e) {
print $e->getMessage();
}
}
}
index.php?class=CidadeControl&method=listar
30. Adianti Solutions Ltda © Pablo Dall'Oglio Programando para Programadores #30
Template View
●
Você precisa caprichar no Visual;
●
Os componentes prontos não são suficientes;
●
Não cometa o erro de ecoar HTML do seu Controller;
●
Você precisa misturar conteúdo dinâmico e estático;
●
Templates permitem separar as coisas (PHP/HTML);
●
HTML com pequenas marcações em seu conteúdo;
●
Marcações são substituídas por conteúdo dinâmico;
●
Permite substituição, repetição;
●
Permite isolar chamadas de bibliotecas (jQuery, Bootstrap);
●
Quando a biblioteca muda, é necessário atualizá-lo (!SASS, LESS).
31. Adianti Solutions Ltda © Pablo Dall'Oglio Programando para Programadores #31
Html Renderer (AF)
<!--[main]-->
<table class="tform" style="border:1px solid #B7B7B7">
<tr> <td colspan="2">Customer data</div></td> </tr>
<tr>
<td width="50%"> ID </td>
<td width="50%"> {$id} </td>
</tr>
<tr>
<td width="50%"> Name </td>
<td width="50%"> {$name} </td>
</tr>
<tr>
<td width="50%"> Address </td>
<td width="50%"> {$address} </td>
</tr>
</table>
<!--[/main]-->
Replaces
32. Adianti Solutions Ltda © Pablo Dall'Oglio Programando para Programadores #32
Html Renderer (AF)
app/control/TemplateController.php
class TemplateController extends TPage
{
public function exibe()
{
$html = new THtmlRenderer('app/resources/customer.html');
TTransaction::open('samples');
$customer = Customer::find(1);
$replace = ['code' => $customer->id,
'name' => $customer->name,
'address' => $customer->address];
$html->enableSection('main', $replace);
$html->show();
TTransaction::close();
}
}
34. Adianti Solutions Ltda © Pablo Dall'Oglio Programando para Programadores #34
#Go Horse 2
class ContaReceber
{
function inserir($id, $a, $b, $c) {
$sql = "INSERT INTO conta_receber...";
// exec $sql;
}
function listar() {
$sql = "SELECT * FROM conta_receber";
// exec $sql
}
function getContasEmAberto() {
$sql = "SELECT id, sum(valor)
FROM contas_receber cr, lancamentos l
WHERE l.conta_id = cr.id
GROUP BY 1 HAVING sum(valor) >1”;
}
function getContasEmAtraso() {
$sql = "SELECT ...
...
WHERE dt_vencimento <= date(now())";
}
}
Lógicas complexas
extensas em SQL
10 piores SQL.pdf
Começou a separar
Código reflexo do BD
Pensamento estruturado
35. Adianti Solutions Ltda © Pablo Dall'Oglio Programando para Programadores #35
Mapeamento Obj-Rel
●
BDR surgiram na década 70 (padrão estruturado);
●
BDR não suportam diversos conceitos OO (herança,
composição, agregação, polimorfismo, métodos, etc);
●
BDOO ainda tem pouca adoção (desempenho inferior, pouca
documentação, ferramentas não tão maduras);
●
BDR são amplamente utilizados para armazenar objetos;
●
Há uma dissonância corrigida pelo uso de técnicas MOR;
●
Muitas ferramentas de persistência surgiram;
●
Persistência significa continuar a existir, perseverar;
●
Objetos existirem em um meio externo à aplicação;
●
Vamos ver algumas técnicas.
36. Adianti Solutions Ltda © Pablo Dall'Oglio Programando para Programadores #36
Table Data Gateway
●
Uma classe responsável por persistir (inserir, alterar, excluir) e
retornar dados do BD;
●
Uma (1) classe por tabela do banco de dados. Apenas uma
instância desta classe irá manipular todos os registros;
●
Stateless: É necessário sempre identificar o registro sobre o
qual o método estará operando;
37. Adianti Solutions Ltda © Pablo Dall'Oglio Programando para Programadores #37
Table Data Gateway
<?php
class ProdutoGateway
{
private static $conn;
public static function setConnection( PDO $conn )
{
self::$conn = $conn;
}
public function find($id, $class = 'stdClass')
{
$sql = "SELECT * FROM produto where id = '$id' ";
$result = self::$conn->query($sql);
return $result->fetchObject($class);
}
public function save($data)
{
if (empty($data->id)) {
$sql = "INSERT INTO produto (descricao, estoque, ...)".
" VALUES ('{$id}', '{$data->descricao}', ... )";
}
Injeção de dependência
Usada pela Model
INSERT or UPDATE
38. Adianti Solutions Ltda © Pablo Dall'Oglio Programando para Programadores #38
Table Data Gateway
<?php
class Produto
{
private $data;
function __get($prop) {}
function __set($prop, $value) {}
public static function find($id)
{
$gw = new ProdutoGateway;
return $gw->find($id, 'Produto');
}
public function save()
{
$gw = new ProdutoGateway;
return $gw->save( (object) $this->data);
}
public function getMargemLucro() {}
public function registraCompra($custo, $quantidade) {}
}
Model
Chamada do Gateway
Lógica de negócios
39. Adianti Solutions Ltda © Pablo Dall'Oglio Programando para Programadores #39
Active Record
●
Classe que conjuga lógica e persistência;
●
Um (1) objeto por linha do banco de dados;
●
Statefull: Retém os dados do objeto corrente.
40. Adianti Solutions Ltda © Pablo Dall'Oglio Programando para Programadores #40
Layer Supertype
●
Métodos se repetem (load, update, delete, ...);
●
Métodos podem ser generalizados se seguirmos convenções;
●
Vamos criar uma superclasse para persistência;
●
Herdada por todos objetos de negócio;
●
Ela implementará métodos de maneira genérica;
●
Layer Supertype: Superclasse para uma camada inteira;
●
Funcionalidades comuns para todos objetos na superclasse;
●
Métodos de NEGÓCIO ficam na classe filha;
41. Adianti Solutions Ltda © Pablo Dall'Oglio Programando para Programadores #41
Active Record
Armazenar um novo objeto (INSERT).
class Pessoa extends TRecord
{
const TABLENAME = 'tab_pessoas';
const PRIMARYKEY= 'id';
const IDPOLICY = 'max'; // {max, serial}
}
TTransaction::open('samples');
$object = new Pessoa;
$object->name = 'Maria da Silva';
$object->address = 'Rua da Conceicao';
$object->phone = '(51) 8111-2222';
$object->status = 'S';
$object->email = 'maria@email.com';
$object->store(); // armazena o objeto
TTransaction::close(); // fecha a transação.
Business Rules
Supertype
Statefull
42. Adianti Solutions Ltda © Pablo Dall'Oglio Programando para Programadores #42
Active Record
Alterar um objeto já existente (UPDATE).
TTransaction::open('samples'); // abre uma transação
$customer = Customer::find(31); // carrega o cliente 31
if ($customer) // se existe
{
$customer->phone = '51 8111-3333'; // muda o fone
$customer->store(); // armazena o objeto
}
new TMessage('info', 'Objeto atualizado');
TTransaction::close(); // fecha a transação.
INSERT OR UPDATE
STATEFULL
43. Adianti Solutions Ltda © Pablo Dall'Oglio Programando para Programadores #43
Atalhos
Manipular um conjunto de objetos conforme um filtro.
$product = Product::find(2);
$products = Product::all();
$count = User::where('age', '>', 18)->count();
$products = Product::where('name', 'like', '%Computer%')->load();
$products = Product::where('id', '>', '1')->orderBy('price')->load();
$products = Product::where('type', '=', '10')->take(10)->skip(20)->load();
User::where('age', '>', 100)->delete();
$contacts = Customer::find(123)->hasMany('Contact');
$turma = Turma::find(10);
foreach ($turma->getMatriculas() as $matricula)
{
print $matricula->aluno->nome;
}
SQL gerado
com Prepared
NAVEGABILIDADE
entre relações
44. Adianti Solutions Ltda © Pablo Dall'Oglio Programando para Programadores #44
Obrigado
●
Contato:
– pablo.blog.br
– adianti.com.br
– @pablodalloglio
– @adiantisolution
●
Não esquecer de falar do Sorteio!