5. SINGLETON
Representa um estado global do seu código
Programas que usam estado global são difíceis de testar e debugar
Programas que dependem do estado global mascaram suas dependências
6. TIGHT COUPLING
Generalização do problema com Singleton
Se mudar um módulo te obriga a mudar outro módulo
Torna o código difícil de reusar e testar
Para evitar, favorecer composição sobre herança e usar injeção de
dependência sempre que possível
7. UNTESTABILITY
Testes não devem ser difíceis
Deixar de escrever um teste economiza tempo de imediato, mas perde
muito mais depois ”caçando” bugs e testando manualmente (falho)
Se escrever um teste é difícil, o problema está no código
Normalmente, untestability é causada por tight coupling
8. PREMATURE OPTIMIZATION
Não super complique o código para otimizá-lo
Terá apenas custo e não benefício
Meça a performance antes de otimizar (benchmarks)
YAGNI = You Ain’t Gonna Need It (Você não vai precisar disso)
9. INDESCRIPTIVE NAMING
Nomeie classes, métodos, atributos apropriadamente
Não abrevie
Se não consegue achar um nome apropriado para uma classe, talvez a
responsabilidade dela não esteja bem definida.
Linguagem de programação é para humanos
Para o computador, $vlna é o mesmo que $valorLitraoNoAlto
10. DUPLICAÇÃO
Se duplicar código e tiver que fazer um ajuste, terá que mexer em
vários lugares (e se esquecer de um?)
DRY = Don’t Repeat Youself
KISS = Keep It Simple, Stupid!
12. SINGLE RESPONSIBILITY PRINCIPLE
Nunca deve haver mais de uma razão para uma classe mudar
Divida classes grandes
Use camadas
Evite classes God
13. SRP - EXEMPLO
<?php
class Livro
{
function getAutor()
{
return 'João da Silva';
}
function getTitulo()
{
return 'Grande Livro';
}
function virarPagina()
{
// Avança ponteiro de página
}
function mostraPaginaAtual()
{
echo 'Conteúdo da página';
}
}
O que há de errado no código?
14. SRP – EXEMPLO MELHORADO
<?php
class Livro
{
function getTitulo()
{
return 'Grande Livro';
}
function getPaginaAtual()
{
echo 'Conteúdo da página';
}
}
interface Printer
{
function printPage($page);
}
class PlainTextPrinter implements Printer
{
function printPage($page) {
echo $page;
}
}
class HtmlPrinter implements Printer
{
function printPage($page) {
echo '<div style="single-page">' . $page . '</div>';
}
}
$livro = new Livro();
$printer = new HtmlPrinter();
$printer->printPage($livro->getPaginaAtual());
15. OPEN/CLOSE PRINCIPLE
Classes devem ser abertas para expansão, mas fechadas para alteração
Defina todos os atributos como private
Sem variáveis globais
Evite setter (sempre que possível)
16. OCP - EXEMPLO
<?php
class Retangulo
{
public $altura;
public $largura;
}
class Area
{
public function calculaArea(Retangulo $retangulo)
{
return $retangulo->altura * $retangulo->largura;
}
}
17. OCP – EXEMPLO DE VIOLAÇÃO
<?php
class Retangulo
{
public $altura;
public $largura;
}
class Circulo
{
public $radio;
}
class Area
{
public function calculaArea($objeto)
{
if ($objeto instanceof Retangulo) {
return $objeto->altura * $objeto->largura;
} elseif ($objeto instanceof Circulo) {
return $objeto->circulo * $objeto->circulo * PI;
}
}
}
18. OCP – EXEMPLO DE VIOLAÇÃO
<?php
class Retangulo
{
public $altura;
public $largura;
}
class Circulo
{
public $radio;
}
class Area
{
public function calculaArea($objeto)
{
if ($objeto instanceof Retangulo) {
return $objeto->altura * $objeto->largura;
} elseif ($objeto instanceof Circulo) {
return $objeto->circulo * $objeto->circulo * PI;
}
}
}
Tivemos que alterar a classe Area
para poder extendê-la. Ela não é
fechada para modificações = não é
aberta para expansão
19. OCP – EXEMPLO MELHORADO
<?php
abstract class Forma
{
abstract function calculaArea();
}
class Retangulo extends Forma
{
public $altura;
public $largura;
public function calculaArea()
{
return $this->altura * $this->largura;
}
}
class Circulo extends Forma
{
public $radio;
public function calculaArea()
{
return $this->circulo * $this->circulo * PI;
}
}
class Area
{
public function calculaArea(Forma $objeto)
{
return $objeto->calculaArea();
}
}
20. LISKOV SUBSTITUTION PRINCIPLE
Subclasses devem poder ser substituidas por sua classe base
Classes filhas não devem quebrar as definições de suas bases
Objetos num código devem poder ser substituídos por seus subtipos
sem alterar o funcionamento correto do programa
21. LSP - EXEMPLO
<?php
class Retangulo
{
protected $altura;
protected $largura;
public function setLargura($largura)
{ $this->largura = $largura; }
public function setAltura($altura)
{ $this->altura = $altura; }
public function getArea()
{
return $this->altura * $this->largura;
}
}
$retangulo = new Retangulo();
$retangulo->setAltura(10);
$retangulo->setLargura(20);
if ($retangulo->getArea() !== 200) {
throw new Exception('Área errada');
}
0
22. LSP - EXEMPLO DE VIOLAÇÃO
<?php
class Retangulo
{
protected $altura;
protected $largura;
public function setLargura($largura) { $this->largura = $largura; }
public function setAltura($altura) { $this->altura = $altura; }
public function getArea()
{
return $this->altura * $this->largura;
}
}
class Quadrado extends Retangulo
{
public function setLargura($largura)
{ $this->largura = $this->altura = $largura; }
public function setAltura($altura)
{ $this->altura = $this->largura = $altura; }
}
$quadrado = new Quadrado();
$quadrado->setAltura(10);
$quadrado->setLargura(20);
if ($quadrado->getArea() !== 200) {
throw new Exception('Área errada');
}
23. INTERFACE SEGREGATION PRINCIPLE
Melhor ter várias interfaces específicas a uma só genérica
Uma classe não deveria implementar métodos que não usa
Usando ISP você garante low coupling e high coersion
24. ISP - EXEMPLO
<?php
interface Veiculo
{
public function liga();
public function abreMala();
public function numEixos();
public function ehMensalista();
}
class Carro implements Veiculo
{
}
class Estacionamento
{
public function permiteEntrada(Veiculo $veiculo)
{
return $veiculo->ehMensalista();
}
}
class Pedagio
{
public function custo(Veiculo $veiculo)
{
return $veiculo->numEixos() * 5;
}
}
25. ISP – EXEMPLO DE VIOLAÇÃO
<?php
interface Veiculo
{
public function liga();
public function abreMala();
public function numEixos();
public function ehMensalista();
}
class Carro implements Veiculo {}
class Moto implements Veiculo {}
class Estacionamento
{
public function permiteEntrada(Veiculo $veiculo)
{
return $veiculo->ehMensalista();
}
}
class Pedagio
{
public function custo(Veiculo $veiculo)
{
return $veiculo->numEixos() * 5;
}
}
26. ISP – EXEMPLO MELHORADO
<?php
interface Veiculo
{
public function liga();
}
interface Mensalista
{
public function ehMensalista();
}
interface Mala
{
public function abreMala();
}
interface Eixos
{
public function numEixos();
}
class Carro implements Veiculo, Mensalista, Mala, Eixos {}
class Moto implements Veiculo, Mensalista, Eixos {}
class Estacionamento
{
public function permiteEntrada(Mensalista $veiculo)
{
return $veiculo->ehMensalista();
}
}
class Pedagio
{
public function custo(Eixos $veiculo)
{
return $veiculo->numEixos() * 5;
}
}
27. DEPENDENCY INVERSION PRINCIPLE
Módulos de alto nível não devem depender de baixo nível, ambos
devem depender de abstrações
Abstrações não devem depender de detalhes. Detalhes devem
depender de abstrações
Use o mesmo nível de abstração num determinado nível
28. DIP - EXEMPLO
<?php
class PDFReader {
private $book;
function __construct(PDFBook $book) {
$this->book = $book;
}
function read() {
return $this->book->read();
}
}
class PDFBook {
function read() {
return "lendo um livro pdf.";
}
}
class Test extends PHPUnit_Framework_TestCase {
function testItCanReadAPDFBook() {
$b = new PDFBook();
$r = new PDFReader($b);
$this->assertRegExp('/livro pdf/', $r->read());
}
}
29. DIP – EXEMPLO DE VIOLAÇÃO
<?php
class EBookReader {
private $book;
function __construct(PDFBook $book) {
$this->book = $book;
}
function read() {
return $this->book->read();
}
}
class PDFBook {
function read() {
return “lendo um livro pdf.";
}
}
class Test extends PHPUnit_Framework_TestCase {
function testItCanReadAPDFBook() {
$b = new PDFBook();
$r = new EBookReader($b);
$this->assertRegExp('/livro pdf/', $r->read());
}
}
30. DIP – EXEMPLO MELHORADO
<?php
interface EBook {
function read();
}
class EBookReader {
private $book;
function __construct(EBook $book) {
$this->book = $book;
}
function read() {
return $this->book->read();
}
}
class PDFBook implements Ebook {
function read() {
return " lendo um livro pdf.";
}
}
class Test extends PHPUnit_Framework_TestCase {
function testItCanReadAPDFBook() {
$b = new PDFBook();
$r = new EBookReader($b);
$this->assertRegExp('/livro pdf/', $r->read());
}
}
31. DIP – EXEMPLO MELHORADO 2
<?php
interface EBook {
function read();
}
class EBookReader {
private $book;
function __construct(EBook $book) {
$this->book = $book;
}
function read() {
return $this->book->read();
}
}
class PDFBook implements EBook {
function read() {
return “lendo um livro pdf.";
}
}
class MobiBook implements EBook {
function read() {
return “lendo um livro mobi.";
}
}
class Test extends PHPUnit_Framework_TestCase {
function testItCanReadAPDFBook() {
$b = new PDFBook();
$r = new EBookReader($b);
$this->assertRegExp('/livro pdf/', $r->read());
}
function testItCanReadAMobiBook() {
$b = new MobiBook();
$r = new EBookReader($b);
$this->assertRegExp('/livro mobi/', $r->read());
}
}
32. DIP – EXEMPLO MELHORADO 2
<?php
interface EBook {
function read();
}
class EBookReader {
private $book;
function __construct(EBook $book) {
$this->book = $book;
}
function read() {
return $this->book->read();
}
}
class PDFBook implements EBook {
function read() {
return “lendo um livro pdf.";
}
}
class MobiBook implements EBook {
function read() {
return “lendo um livro mobi.";
}
}
class Test extends PHPUnit_Framework_TestCase {
function testItCanReadAPDFBook() {
$b = new PDFBook();
$r = new EBookReader($b);
$this->assertRegExp('/livro pdf/', $r->read());
}
function testItCanReadAMobiBook() {
$b = new MobiBook();
$r = new EBookReader($b);
$this->assertRegExp('/livro mobi/', $r->read());
}
}
• Não precisamos mudar a classe EBooReader = OCP
• Separamos as responsabilidades = SRP
• Segregamos nossas interfaces = ISP
• Usamos corretamente o subtipo = LSP
• DIP nos ajuda a manter os outros 4 princípios