Injeção de
Dependências
Um bom padrão para se começar...
11/2019
Objetivos
▸ Apresentar o conceito de Injeção de Dependências
▸ Explorar a visão sobre os artefatos relacionados à Injeção de Dependências
▸ Promover a reflexão sobre as boas práticas de uso de Injeção de Dependências
2
Apresentação
Formação
▸ Curso Técnico em Processamento de Dados - UNICAMP
▸ Graduação em Publicidade e Propaganda - ISCA
▸ Pós Graduação em Engenharia de Softwares com Métodos Ágeis -
IGTI
3
Vivência Profissional
▸ Sólida experiência em liderança de desenvolvimento de softwares de missão
crítica, responsável por sustentação, desenvolvimento e novos projetos.
▸ Sólidos conhecimentos de arquitetura de software utilizando os paradigmas
de desenvolvimento estruturado (OOP), DDD e micro-serviços, entre outros.
▸ Ampla experiência com ambiente cloud AWS (Amazon Web Services),
satisfazendo questões de resiliência e escalabilidade.
▸ Liderança de equipe DevOps utilizando metodologias ágeis (Scrum/XP),
Kanban e práticas ITIL.
▸ + de 20 anos envolvido com Tecnologia da Informação.
Pessoal
▸ Nascido no Interior Paulista
▸ Casado e pai de 2 filhas
▸ Apaixonado por Tecnologia
▸ Gamer praticante
▸ Apreciador de um bom
churrasco e cerveja gelada =)
Agenda
▸ Injeção de Dependências
▸ Fabricação de Objetos
▸ Inversão de Controle
4
Injeção de
Dependências
Dependency Injection - DI
1
“
Injeção de dependência (“Dependency Injection - DI”) é um
padrão de desenvolvimento (“Design Pattern”) utilizado
para manter baixo o nível de acoplamento na aplicação.
As dependências entre os componentes podem ser
definidas por configuração de infraestrutura (“container”),
que é responsável por "injetar" em cada componente suas
dependências declaradas.
6
7
Classe A - Hello World
class ClassA
{
/**
* Returns Hello "World" or "Name"
* @param string|null $name Any name.
* @return string
*/
public function helloWorld(string $name = null): string
{
$name = (empty($name)) ? "World" : $name;
return "Hello {$name}!" . PHP_EOL;
}
}
class ClassB
{
/**
* Returns Hello Class Name
* @return string
*/
public function helloClass(): string
{
return (new ClassA())->helloWorld(__CLASS__);
}
}
Dependência A - Instanciada
$classB = new ClassB();
echo $classB->helloClass();
// Hello ClassB!
8
Classe A - Hello World
class ClassA
{
/**
* Returns Hello "World" or "Name"
* @param string|null $name Any name.
* @return string
*/
public function helloWorld(string $name = null): string
{
$name = (empty($name)) ? "World" : $name;
return "Hello {$name}!" . PHP_EOL;
}
}
$classB = new ClassB((new ClassA()));
echo $classB->helloClass();
// Hello ClassB!
class ClassB
{
/** @var ClassA */
private $classA;
public function __construct(ClassA $classA)
{
$this->classA = $classA;
}
/**
* Returns Hello Class Name
* @return string
*/
public function helloClass(): string
{
return $this->classA->helloWorld(__CLASS__);
}
}
Dependência A - Injetada
9
Dependência A - Instanciada
class ClassB
{
/**
* Returns Hello Class Name
* @return string
*/
public function helloClass(): string
{
return (new ClassA())->helloWorld(__CLASS__);
}
}
class ClassB
{
/** @var ClassA */
private $classA;
public function __construct(ClassA $classA)
{
$this->classA = $classA;
}
/**
* Returns Hello Class Name
* @return string
*/
public function helloClass(): string
{
return $this->classA->helloWorld(__CLASS__);
}
}
Dependência A - Injetada
Conclusão
10
Ação
▸ Instanciar classes dependentes dentro
de outras classes.
Problemas Gerados
Necessidade de refatoração de todas as
classes que usam a dependência caso:
▸ A assinatura do construtor da classe
dependente for alterada.
▸ A classe dependente for substituída.
Fabricação de
Objetos
Factory | Factory Method
2
“
Fábrica (“Factory”) e Fábrica Dinâmica (“Factory Method”)
são padrões de desenvolvimento (“Design Pattern”)
utilizados para controlar e centralizar a fabricação de
objetos. Sua utilização facilita bastante a adoção de
Injeção de Dependências.
12
13
Classe A - Hello World
class ClassA
{
/**
* Returns Hello "World" or "Name"
* @param string|null $name Any name.
* @return string
*/
public function helloWorld(string $name = null): string
{
$name = (empty($name)) ? "World" : $name;
return "Hello {$name}!" . PHP_EOL;
}
}
class ClassAFactory
{
/**
* Class A Factory
* @return ClassA
*/
public static function factory()
{
return new ClassA();
}
}
$classB = new ClassB(ClassAFactory::factory());
echo $classB->helloClass();
class ClassB
{
/** @var ClassA */
private $classA;
public function __construct(ClassA $classA)
{
$this->classA = $classA;
}
/**
* Returns Hello Class Name
* @return string
*/
public function helloClass(): string
{
return $this->classA->helloWorld(__CLASS__);
}
}
Dependência A - Injetada
14
Classe B - Injetando Classe A
class ClassB
{
/** @var ClassA */
private $classA;
public function __construct(ClassA $classA)
{
$this->classA = $classA;
}
/**
* Returns Hello Class Name
* @return string
*/
public function helloClass(): string
{
return $this->classA->helloWorld(__CLASS__);
}
}
$classB = ClassBFactory::factory();
echo $classB->helloClass();
class ClassBFactory
{
/**
* Class A Factory
* @return ClassB
*/
public static function factory()
{
new ClassB(ClassAFactory::factory());
}
}
Fábrica da Classe B
Conclusão
15
Ação
▸ Alterar o construtor da classe
dependente a ser injetada.
Problemas Gerados
Necessidade de refatoração de todas as
classes que injetam a dependência.
Inversão de
Controle
Inversion of Control - IoC
3
“
Inversão de Controle (“Inversion of Control - IoC”) faz a
inversão da dependência baixando o acoplamento, ou
seja, ao invés da classe principal saber de qual classe
concreta ela depende, ela delega isso para a fábrica, que
retorna a implementação apropriada para aquela
interface. Com isso, passamos a depender de uma
abstração, facilitando a manutenção e evolução da
aplicação.
17
18
Classe N - Usando Interface A
interface ClassAInterface
{
/** … */
public function helloWorld(string $name = null): string;
}
class ClassN implements ClassAInterface
{
/** @inheritDoc */
public function helloWorld(string $name = null): string
{
$name = (empty($name)) ? "World" : $name;
return "Hello {$name}!" . PHP_EOL;
}
}
class ClassAFactory
{
/**
* Class A Factory
* @return ClassAInterface
*/
public static function factory(): ClasseAInterface
{
return new ClassN();
}
}
$classB = ClassBFactory::factory();
echo $classB->helloClass();
class ClassB
{
/** @var ClassAInterface */
private $classA;
public function __construct(ClassAInterface $classA)
{
$this->classA = $classA;
}
/**
* Returns Hello Class Name
* @return string
*/
public function helloClass(): string
{
return $this->classA->helloWorld(__CLASS__);
}
}
Classe B - Dependência de Interface
19
Laravel Service Provider - Conteiner para DI (mapeamento)
use IlluminateSupportServiceProvider;
/**
* Class ClassAServiceProvider
* @package AppProviders
*/
class ClassAServiceProvider extends ServiceProvider
{
/**
* Register any application services.
*
* @return void
*/
public function register()
{
$this->app->singleton(ClassAInterface::class, function ($app) {
return new ClassN();
});
}
}
$classA = $this->app->get(ClassAInterface::class).
Conclusão
20
Ação
▸ Alterar a assinatura do construtor ou
alterar a própria classe dependente.
Problemas Gerados
Necessidade de refatoração de todas as
classes que injetam a dependência.
Dúvidas?
21
“A melhor maneira de prever o
futuro é inventá-lo.”
22
Danilo D. de Godoy
▸ Arquiteto, Engenheiro e Coordenador de Software (TI)
▸ danilo.godoy@totalexpress.com.br
▸ https://www.linkedin.com/in/danilodoring/
Alan Kay, cientista da computação, 1971

Injeção de Dependências com PHP

  • 1.
    Injeção de Dependências Um bompadrão para se começar... 11/2019
  • 2.
    Objetivos ▸ Apresentar oconceito de Injeção de Dependências ▸ Explorar a visão sobre os artefatos relacionados à Injeção de Dependências ▸ Promover a reflexão sobre as boas práticas de uso de Injeção de Dependências 2
  • 3.
    Apresentação Formação ▸ Curso Técnicoem Processamento de Dados - UNICAMP ▸ Graduação em Publicidade e Propaganda - ISCA ▸ Pós Graduação em Engenharia de Softwares com Métodos Ágeis - IGTI 3 Vivência Profissional ▸ Sólida experiência em liderança de desenvolvimento de softwares de missão crítica, responsável por sustentação, desenvolvimento e novos projetos. ▸ Sólidos conhecimentos de arquitetura de software utilizando os paradigmas de desenvolvimento estruturado (OOP), DDD e micro-serviços, entre outros. ▸ Ampla experiência com ambiente cloud AWS (Amazon Web Services), satisfazendo questões de resiliência e escalabilidade. ▸ Liderança de equipe DevOps utilizando metodologias ágeis (Scrum/XP), Kanban e práticas ITIL. ▸ + de 20 anos envolvido com Tecnologia da Informação. Pessoal ▸ Nascido no Interior Paulista ▸ Casado e pai de 2 filhas ▸ Apaixonado por Tecnologia ▸ Gamer praticante ▸ Apreciador de um bom churrasco e cerveja gelada =)
  • 4.
    Agenda ▸ Injeção deDependências ▸ Fabricação de Objetos ▸ Inversão de Controle 4
  • 5.
  • 6.
    “ Injeção de dependência(“Dependency Injection - DI”) é um padrão de desenvolvimento (“Design Pattern”) utilizado para manter baixo o nível de acoplamento na aplicação. As dependências entre os componentes podem ser definidas por configuração de infraestrutura (“container”), que é responsável por "injetar" em cada componente suas dependências declaradas. 6
  • 7.
    7 Classe A -Hello World class ClassA { /** * Returns Hello "World" or "Name" * @param string|null $name Any name. * @return string */ public function helloWorld(string $name = null): string { $name = (empty($name)) ? "World" : $name; return "Hello {$name}!" . PHP_EOL; } } class ClassB { /** * Returns Hello Class Name * @return string */ public function helloClass(): string { return (new ClassA())->helloWorld(__CLASS__); } } Dependência A - Instanciada $classB = new ClassB(); echo $classB->helloClass(); // Hello ClassB!
  • 8.
    8 Classe A -Hello World class ClassA { /** * Returns Hello "World" or "Name" * @param string|null $name Any name. * @return string */ public function helloWorld(string $name = null): string { $name = (empty($name)) ? "World" : $name; return "Hello {$name}!" . PHP_EOL; } } $classB = new ClassB((new ClassA())); echo $classB->helloClass(); // Hello ClassB! class ClassB { /** @var ClassA */ private $classA; public function __construct(ClassA $classA) { $this->classA = $classA; } /** * Returns Hello Class Name * @return string */ public function helloClass(): string { return $this->classA->helloWorld(__CLASS__); } } Dependência A - Injetada
  • 9.
    9 Dependência A -Instanciada class ClassB { /** * Returns Hello Class Name * @return string */ public function helloClass(): string { return (new ClassA())->helloWorld(__CLASS__); } } class ClassB { /** @var ClassA */ private $classA; public function __construct(ClassA $classA) { $this->classA = $classA; } /** * Returns Hello Class Name * @return string */ public function helloClass(): string { return $this->classA->helloWorld(__CLASS__); } } Dependência A - Injetada
  • 10.
    Conclusão 10 Ação ▸ Instanciar classesdependentes dentro de outras classes. Problemas Gerados Necessidade de refatoração de todas as classes que usam a dependência caso: ▸ A assinatura do construtor da classe dependente for alterada. ▸ A classe dependente for substituída.
  • 11.
  • 12.
    “ Fábrica (“Factory”) eFábrica Dinâmica (“Factory Method”) são padrões de desenvolvimento (“Design Pattern”) utilizados para controlar e centralizar a fabricação de objetos. Sua utilização facilita bastante a adoção de Injeção de Dependências. 12
  • 13.
    13 Classe A -Hello World class ClassA { /** * Returns Hello "World" or "Name" * @param string|null $name Any name. * @return string */ public function helloWorld(string $name = null): string { $name = (empty($name)) ? "World" : $name; return "Hello {$name}!" . PHP_EOL; } } class ClassAFactory { /** * Class A Factory * @return ClassA */ public static function factory() { return new ClassA(); } } $classB = new ClassB(ClassAFactory::factory()); echo $classB->helloClass(); class ClassB { /** @var ClassA */ private $classA; public function __construct(ClassA $classA) { $this->classA = $classA; } /** * Returns Hello Class Name * @return string */ public function helloClass(): string { return $this->classA->helloWorld(__CLASS__); } } Dependência A - Injetada
  • 14.
    14 Classe B -Injetando Classe A class ClassB { /** @var ClassA */ private $classA; public function __construct(ClassA $classA) { $this->classA = $classA; } /** * Returns Hello Class Name * @return string */ public function helloClass(): string { return $this->classA->helloWorld(__CLASS__); } } $classB = ClassBFactory::factory(); echo $classB->helloClass(); class ClassBFactory { /** * Class A Factory * @return ClassB */ public static function factory() { new ClassB(ClassAFactory::factory()); } } Fábrica da Classe B
  • 15.
    Conclusão 15 Ação ▸ Alterar oconstrutor da classe dependente a ser injetada. Problemas Gerados Necessidade de refatoração de todas as classes que injetam a dependência.
  • 16.
  • 17.
    “ Inversão de Controle(“Inversion of Control - IoC”) faz a inversão da dependência baixando o acoplamento, ou seja, ao invés da classe principal saber de qual classe concreta ela depende, ela delega isso para a fábrica, que retorna a implementação apropriada para aquela interface. Com isso, passamos a depender de uma abstração, facilitando a manutenção e evolução da aplicação. 17
  • 18.
    18 Classe N -Usando Interface A interface ClassAInterface { /** … */ public function helloWorld(string $name = null): string; } class ClassN implements ClassAInterface { /** @inheritDoc */ public function helloWorld(string $name = null): string { $name = (empty($name)) ? "World" : $name; return "Hello {$name}!" . PHP_EOL; } } class ClassAFactory { /** * Class A Factory * @return ClassAInterface */ public static function factory(): ClasseAInterface { return new ClassN(); } } $classB = ClassBFactory::factory(); echo $classB->helloClass(); class ClassB { /** @var ClassAInterface */ private $classA; public function __construct(ClassAInterface $classA) { $this->classA = $classA; } /** * Returns Hello Class Name * @return string */ public function helloClass(): string { return $this->classA->helloWorld(__CLASS__); } } Classe B - Dependência de Interface
  • 19.
    19 Laravel Service Provider- Conteiner para DI (mapeamento) use IlluminateSupportServiceProvider; /** * Class ClassAServiceProvider * @package AppProviders */ class ClassAServiceProvider extends ServiceProvider { /** * Register any application services. * * @return void */ public function register() { $this->app->singleton(ClassAInterface::class, function ($app) { return new ClassN(); }); } } $classA = $this->app->get(ClassAInterface::class).
  • 20.
    Conclusão 20 Ação ▸ Alterar aassinatura do construtor ou alterar a própria classe dependente. Problemas Gerados Necessidade de refatoração de todas as classes que injetam a dependência.
  • 21.
  • 22.
    “A melhor maneirade prever o futuro é inventá-lo.” 22 Danilo D. de Godoy ▸ Arquiteto, Engenheiro e Coordenador de Software (TI) ▸ danilo.godoy@totalexpress.com.br ▸ https://www.linkedin.com/in/danilodoring/ Alan Kay, cientista da computação, 1971