O documento apresenta os conceitos de Injeção de Dependências, Fabricação de Objetos e Inversão de Controle. Estes padrões de desenvolvimento visam reduzir o acoplamento entre classes e facilitar a manutenção do código, permitindo que as dependências sejam definidas por configuração e injetadas através de fábricas.
2. 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
3. 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 =)
4. Agenda
▸ Injeção de Dependências
▸ Fabricação de Objetos
▸ Inversão de Controle
4
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 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.
12. “
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. 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 o construtor da classe
dependente a ser injetada.
Problemas Gerados
Necessidade de refatoração de todas as
classes que injetam a dependência.
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 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.
22. “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