princípios solid · 8 end masterclass contém ... 12 aberto/fechado definição paf ... i os...

67
Instituto de Matemática e Estatística Universidade de São Paulo Princípios SOLID Caio Costa Salgado Leonardo Pereira Macedo Rodrigo Siqueira Jordão 22 de Junho de 2016

Upload: phunglien

Post on 27-Nov-2018

212 views

Category:

Documents


0 download

TRANSCRIPT

Instituto de Matemática e EstatísticaUniversidade de São Paulo

Princípios SOLID

Caio Costa SalgadoLeonardo Pereira MacedoRodrigo Siqueira Jordão

22 de Junho de 2016

1

Sumário

Introdução

Responsabilidade ÚnicaLCOM

Aberto/FechadoPadrões de projeto úteisImplementando novos comportamentos

Substituição de Liskov

Injeção de Dependência

Lei de Demeter

Seminário POO | Princípios SOLID

2

IntroduçãoPadrões e Antipadrões

I Padrões de projetoI Solução reutilizável de um problema em design de softwareI Melhoram a qualidade e organização das classes

I AntipadrõesI Ineficientes, arriscados e contraprodutivosI Podem ser identificados pelo mau cheiro de projeto que criam

Seminário POO | Princípios SOLID

2

IntroduçãoPadrões e Antipadrões

I Padrões de projetoI Solução reutilizável de um problema em design de softwareI Melhoram a qualidade e organização das classes

I AntipadrõesI Ineficientes, arriscados e contraprodutivosI Podem ser identificados pelo mau cheiro de projeto que criam

Seminário POO | Princípios SOLID

3

Princípios SOLIDIntrodução

I Acrônimo para 5 princípios de POOI Criado por Robert C. Martin (Uncle Bob)

por volta do ano 2000

I Diminui o acoplamento entre classesI Separa as responsabilidades para melhorar

o código da aplicação desenvolvida

Seminário POO | Princípios SOLID

3

Princípios SOLIDIntrodução

I Acrônimo para 5 princípios de POOI Criado por Robert C. Martin (Uncle Bob)

por volta do ano 2000I Diminui o acoplamento entre classesI Separa as responsabilidades para melhorar

o código da aplicação desenvolvida

Seminário POO | Princípios SOLID

4

Acrônimo SOLIDIntrodução

S ingle Responsibility

Open/Closed

L iskov Substitution

I njection of Dependencies

D emeter Principle

Seminário POO | Princípios SOLID

5

SOLID: Responsabilidade Única

Seminário POO | Princípios SOLID

6

Responsabilidade ÚnicaDefinição

PRU - Princípio de Responsabilidade ÚnicaUma classe deve ter uma, e apenas uma, responsabilidade (isto é,apenas uma razão para mudar)

I Uma responsabilidade pode ser descrita com 25 ou menospalavras

I Falta de coesão pode indicar uma violação do PRU

Seminário POO | Princípios SOLID

7

Responsabilidade ÚnicaExemplo

1 c lass MasterClass2 def p e r f o r m I n i t i a l i z a t i o n . . . ; end3 def readFromFile . . . ; end4 def w r i t e T o F i l e . . . ; end5 def displayToScreen . . . ; end6 def per fo rmCa lcu la t ion . . . ; end7 def v a l i d a t e I n p u t . . . ; end8 end

MasterClass contém responsabilidades diversas e poucorelacionadas

Seminário POO | Princípios SOLID

7

Responsabilidade ÚnicaExemplo

1 c lass MasterClass2 def p e r f o r m I n i t i a l i z a t i o n . . . ; end3 def readFromFile . . . ; end4 def w r i t e T o F i l e . . . ; end5 def displayToScreen . . . ; end6 def per fo rmCa lcu la t ion . . . ; end7 def v a l i d a t e I n p u t . . . ; end8 end

MasterClass contém responsabilidades diversas e poucorelacionadas

Seminário POO | Princípios SOLID

8

Responsabilidade ÚnicaExemplo

Solução: Separar em classes de acordo com a responsabilidade

1 c lass F i l e Inpu tOu tpu t2 def readFromFile . . . ; end3 def w r i t e T o F i l e . . . ; end4 end

1 c lass UserInputOutput2 def displayToScreen . . . ; end3 def v a l i d a t e I n p u t . . . ; end4 end

1 c lass Logic2 def p e r f o r m I n i t i a l i z a t i o n . . . ; end3 def per fo rmCa lcu la t ion . . . ; end4 end

Seminário POO | Princípios SOLID

9

Responsabilidade ÚnicaLCOM

I LCOM: Lack of Cohesion of MethodsI Analisa a coesão de uma classe, medindo se ela consiste em

múltiplos "aglomerados"I Duas variantes principais:

Variante Pontuação Interpretação

Henderson-Sellers 0 a 1Quanto mais próximo de 1, maisvariáveis de instância são aces-sadas por apenas um método

LCOM-4 1 a nSe n > 1, então n-1 responsabili-dades podem ser extraídas parasuas próprias classes

Seminário POO | Princípios SOLID

10

Responsabilidade ÚnicaLCOM-4

I Dois métodos estão relacionados se:I Acessam a mesma variável de instância/classeI Um chama o outro

I LCOM-4 conecta métodos relacionados em um grafoI Se o número n de grafos resultantes for maior que 1, pode-se

dividir em classe em partes menores

Seminário POO | Princípios SOLID

10

Responsabilidade ÚnicaLCOM-4

I Dois métodos estão relacionados se:I Acessam a mesma variável de instância/classeI Um chama o outro

I LCOM-4 conecta métodos relacionados em um grafoI Se o número n de grafos resultantes for maior que 1, pode-se

dividir em classe em partes menores

Seminário POO | Princípios SOLID

10

Responsabilidade ÚnicaLCOM-4

I Dois métodos estão relacionados se:I Acessam a mesma variável de instância/classeI Um chama o outro

I LCOM-4 conecta métodos relacionados em um grafoI Se o número n de grafos resultantes for maior que 1, pode-se

dividir em classe em partes menores

Exemplo 1: LCOM-4 = 2

Seminário POO | Princípios SOLID

10

Responsabilidade ÚnicaLCOM-4

I Dois métodos estão relacionados se:I Acessam a mesma variável de instância/classeI Um chama o outro

I LCOM-4 conecta métodos relacionados em um grafoI Se o número n de grafos resultantes for maior que 1, pode-se

dividir em classe em partes menores

Exemplo 2: LCOM-4 = 1

Seminário POO | Princípios SOLID

11

SOLID: Aberto/Fechado

Seminário POO | Princípios SOLID

12

Aberto/FechadoDefinição

PAF - Princípio Aberto/FechadoUma classe deve ser aberta para extensão, mas fechada paramodificação

I Deseja-se estender o comportamento de classes sem modificarcódigo existente na qual dependem

Seminário POO | Princípios SOLID

13

Aberto/FechadoExemplo

1 c lass Report2 def output3 f o r m a t t e r =4 case @format5 when : html6 HtmlFormatter . new( s e l f )7 when : pdf8 PdfFormatter . new( s e l f )9 end

10 end11 end

I Cheiro de código Comando Case...I Cirurgia de Espingarda: Adicionar

um novo tipo de Formatter exigirámudanças em um ou mais métodos

Como resolver? Padrões de projeto!

Seminário POO | Princípios SOLID

13

Aberto/FechadoExemplo

1 c lass Report2 def output3 f o r m a t t e r =4 case @format5 when : html6 HtmlFormatter . new( s e l f )7 when : pdf8 PdfFormatter . new( s e l f )9 end

10 end11 end

I Cheiro de código Comando Case...

I Cirurgia de Espingarda: Adicionarum novo tipo de Formatter exigirámudanças em um ou mais métodos

Como resolver? Padrões de projeto!

Seminário POO | Princípios SOLID

13

Aberto/FechadoExemplo

1 c lass Report2 def output3 f o r m a t t e r =4 case @format5 when : html6 HtmlFormatter . new( s e l f )7 when : pdf8 PdfFormatter . new( s e l f )9 end

10 end11 end

I Cheiro de código Comando Case...I Cirurgia de Espingarda: Adicionar

um novo tipo de Formatter exigirámudanças em um ou mais métodos

Como resolver? Padrões de projeto!

Seminário POO | Princípios SOLID

13

Aberto/FechadoExemplo

1 c lass Report2 def output3 f o r m a t t e r =4 case @format5 when : html6 HtmlFormatter . new( s e l f )7 when : pdf8 PdfFormatter . new( s e l f )9 end

10 end11 end

I Cheiro de código Comando Case...I Cirurgia de Espingarda: Adicionar

um novo tipo de Formatter exigirámudanças em um ou mais métodos

Como resolver?

Padrões de projeto!

Seminário POO | Princípios SOLID

13

Aberto/FechadoExemplo

1 c lass Report2 def output3 f o r m a t t e r =4 case @format5 when : html6 HtmlFormatter . new( s e l f )7 when : pdf8 PdfFormatter . new( s e l f )9 end

10 end11 end

I Cheiro de código Comando Case...I Cirurgia de Espingarda: Adicionar

um novo tipo de Formatter exigirámudanças em um ou mais métodos

Como resolver? Padrões de projeto!

Seminário POO | Princípios SOLID

14

Aberto/FechadoSolução com Fábrica Abstrata

1 c lass Report2 def output3 f o rma t te r_c lass =4 begin5 @format . to_s . c l a s s i f y . cons tan t i ze6 rescue NameError7 # Handle " i n v a l i d f o r m a t t e r type "8 end9 f o r m a t t e r = fo rma t te r_c lass . send ( : new , s e l f )

10 end11 end

I @format se refere a um símbolo (:pdf, :html)

I Duck Typing: A partir do símbolo, adquirimos uma referênciapara a classe desejada e chamamos seu construtor

Seminário POO | Princípios SOLID

14

Aberto/FechadoSolução com Fábrica Abstrata

1 c lass Report2 def output3 f o rma t te r_c lass =4 begin5 @format . to_s . c l a s s i f y . cons tan t i ze6 rescue NameError7 # Handle " i n v a l i d f o r m a t t e r type "8 end9 f o r m a t t e r = fo rma t te r_c lass . send ( : new , s e l f )

10 end11 end

I @format se refere a um símbolo (:pdf, :html)I Duck Typing: A partir do símbolo, adquirimos uma referência

para a classe desejada e chamamos seu construtor

Seminário POO | Princípios SOLID

15

Aberto/FechadoSolução com Template

I Os passos (métodos) da tarefa (formatação) são os mesmospara todas as variantes de Formatter

I Implementação dos métodos de cada subclasse podem divergir

Seminário POO | Princípios SOLID

16

Aberto/FechadoSolução com Strategy

I Usando Strategy, os passos podem ser diferentes em cadasubclasse

Seminário POO | Princípios SOLID

17

Aberto/FechadoQueremos Novos Comportamentos!

I E se quisermos adicionar um novo comportamento em umaclasse existente? Por exemplo, arquivos PDF:

I Com/sem proteção de senhaI Com/sem uma marca d’água "rascunho"

I Uma possível ideia:

Não é DRY!

Seminário POO | Princípios SOLID

17

Aberto/FechadoQueremos Novos Comportamentos!

I E se quisermos adicionar um novo comportamento em umaclasse existente? Por exemplo, arquivos PDF:

I Com/sem proteção de senhaI Com/sem uma marca d’água "rascunho"

I Uma possível ideia:

Não é DRY!

Seminário POO | Princípios SOLID

17

Aberto/FechadoQueremos Novos Comportamentos!

I E se quisermos adicionar um novo comportamento em umaclasse existente? Por exemplo, arquivos PDF:

I Com/sem proteção de senhaI Com/sem uma marca d’água "rascunho"

I Uma possível ideia:

Não é DRY!

Seminário POO | Princípios SOLID

18

Aberto/FechadoPadrão Decorator

Padrão Decorator: "Decoramos" a classe ao envolvê-la em umaversão melhorada, com mesma interface

Código fonteSeminário POO | Princípios SOLID

19

SOLID: Substituição de Liskov

Seminário POO | Princípios SOLID

20

Substituição de LiskovDefinição

Princípio de LiskovUm método projetado para trabalhar em umobjeto de tipo T deve também trabalhar em umobjeto de qualquer subtipo de T

I Herança é muito util para a reutilização de código, mas não é sópor isso que ela deve ser usada

I A herança é um compartilhamento de implementação. Se asubclasse não ganha vantagem com a implementação herdada,talvez ela não devesse ser uma subclasse

Seminário POO | Princípios SOLID

21

Substituição de LiskovExemplo

1 c lass Retangulo2 a t t r_accessor : la rgura , : a l t u ra , : canto_ in f_esq3 def new( la rgura , a l t u ra , canto_ in f_esq ) . . . ; end4 def area . . . ; end5 def dobrar_a l tu ra_sobre_a_ largura ( dim )6 s e l f . l a rgu ra = 2∗dim7 s e l f . a l t u r a = dim8 end9 end

10 c lass Quadrado < Retangulo11 a t t r _ r e a d e r : la rgura , : a l t u ra , : lado12 def l a rgu ra =(w) ; @largura = @altura = w ; end13 def a l t u r a =(w) ; @largura = @altura = w ; end14 def lado =(w) ; @largura = @altura = w ; end15 end

Seminário POO | Princípios SOLID

22

Substituição de LiskovCheiro

Mau cheiroI Modificação do funcionamento do método herdadoI Nesse caso, não faz sentido dobrar altura sobre a largura para

um quadradoI Método da superclasse jogado fora

Seminário POO | Princípios SOLID

23

Substituição de LiskovRefatoração

1 c lass Quadrado2 a t t r_accessor : r e t3 def i n i t i a l i z e ( : lado , : canto_ in f_esq )4 @ret = Retangulo . new( lado , lado , canto_ in f_esq )5 end67 def area8 r e t . area9 end

1011 def lado =( s )12 r e c t . width = r e c t . he igh t = s13 end14 end

Trocando herança por composição: implementação é delegada, enão herdada

Seminário POO | Princípios SOLID

23

Substituição de LiskovRefatoração

1 c lass Quadrado2 a t t r_accessor : r e t3 def i n i t i a l i z e ( : lado , : canto_ in f_esq )4 @ret = Retangulo . new( lado , lado , canto_ in f_esq )5 end67 def area8 r e t . area9 end

1011 def lado =( s )12 r e c t . width = r e c t . he igh t = s13 end14 end

Trocando herança por composição: implementação é delegada, enão herdada

Seminário POO | Princípios SOLID

24

Substituição de LiskovRefatoração

Delegação em Ruby: ForwardableMódulo em Ruby que implementa a delegação

1 c lass Quadrado2 extend Forwardable3 def_de legators : @ret , : area , : per imetro , : rotacao45 def i n i t i a l i z e ( : lado , : canto_ in f_esq )6 @ret = Retangulo . new( lado , lado , canto_ in f_esq )7 end89 def lado =( s )

10 @ret . l a rgu ra = @ret . a l t u r a = s11 end12 end

Seminário POO | Princípios SOLID

25

Substituição de Liskov

ResumoToda a implementação da super classe deve fazer sentido para assuas subclasses

Seminário POO | Princípios SOLID

26

SOLID: Injeção de Dependência

Seminário POO | Princípios SOLID

27

Injeção de DependêciaDefinição

Injeção de dependênciaI Se duas classes dependem uma da outra, mas suas

implementações podem mudar, seria bom para ambasdependerem de uma interface abstrata separada que seja"injetada" entre elas

I O Princípio de Injeção de Dependência (PID) é a criaçãode uma interface com o objetivo de tratar a manipulaçãode objetos de forma correta em tempo de execução

Seminário POO | Princípios SOLID

27

Injeção de DependêciaDefinição

Injeção de dependênciaI Se duas classes dependem uma da outra, mas suas

implementações podem mudar, seria bom para ambasdependerem de uma interface abstrata separada que seja"injetada" entre elas

I O Princípio de Injeção de Dependência (PID) é a criaçãode uma interface com o objetivo de tratar a manipulaçãode objetos de forma correta em tempo de execução

Seminário POO | Princípios SOLID

28

Injeção de DependêciaExemplo

1 c lass Ema i l L i s t2 a t t r _ r e a d e r : ma i le r3 delegate : send_email , : to => : ma i le r4 def i n i t i a l i z e5 @mailer = MailerMonkey . new6 end7 end8 # i n RottenPotatoes E m a i l L i s t C o n t r o l l e r :9 def adver t i se_d iscount_ fo r_mov ie

10 moviegoers = Moviegoer . i n t e r e s t e d _ i n params [ :movie_id ]

11 Ema i l L i s t . new . send_email_to moviegoers12 end

Seminário POO | Princípios SOLID

29

Injeção de DependêciaExemplo

I Se quisermos adicionar novas maneiras para enviar mensagens,seria necessário modificar o funcionamento do controller,adicionando condicionais

I Nesse caso, entra em ação o Princípio de Injeção deDependência (PID)!

Seminário POO | Princípios SOLID

30

Injeção de DependêciaExemplo - Refatoração

Controller

1 def adver t i se_d iscount_ fo r_mov ie2 moviegoers = Moviegoer . i n t e r e s t e d _ i n ( params [ :

movie_id ] )3 Ema i l L i s t . new( Conf ig . emai le r ) . send_email_to (

moviegoers )4 end5 end

Seminário POO | Princípios SOLID

31

Injeção de DependêciaExemplo - Refatoração

Config Class

1 c lass Conf ig2 def s e l f . emai ler3 i f emai l_d isab led? then N u l l M a i l e r e lse4 i f has_amiko? then AmikoAdapter e lse

MailerMonkey end5 end6 end7 end

Seminário POO | Princípios SOLID

32

Injeção de DependêciaExemplo - Refatoração

AmikoAdapter Class

1 c lass AmikoAdapter2 def i n i t i a l i z e ; @amiko = Amiko . new ( . . . ) ; end3 def send_email4 @amiko . au then t i ca te ( . . . )5 @amiko . send_message ( . . . )6 end7 end

Seminário POO | Princípios SOLID

33

Injeção de DependêciaPadrões de Projeto

PID pode ser uma aplicação de um padrãoI FachadaI Fábrica abstrata: Cria diferentes tipos de objetos com o mesmo

objetivoI Adaptador: Interface que modifica a interação com uma classe

com o objetivo de padronizar o acesso (no nosso caso)I Proxy: Mesmo comportamento de outra classe, mas com

tratamento para casos "estranhos"

Seminário POO | Princípios SOLID

34

SOLID: Lei de Demeter

Seminário POO | Princípios SOLID

35

Lei de DemeterDefinição

Princípio de DemeterUm método pode chamar outros métodos em sua própria classe emétodos nas classes de suas próprias variáveis de instância; todo oresto é tabu

Conselhos...Converse com seus amigos - Não fique íntimode estranhos

Seminário POO | Princípios SOLID

35

Lei de DemeterDefinição

Princípio de DemeterUm método pode chamar outros métodos em sua própria classe emétodos nas classes de suas próprias variáveis de instância; todo oresto é tabu

Conselhos...Converse com seus amigos - Não fique íntimode estranhos

Seminário POO | Princípios SOLID

36

Lei de DemeterDemeter na Prática

Seus parâmetrosQuando o seu método recebe parâmetros, ele pode chamar algummétodo fornecido por este parâmetro diretamente

1 c lass JobPost2 def pos t_u r l ( i d )3 ’ h t t p : / / www. k u n i r i . org / posts / # { i d } ’4 end5 end

Seminário POO | Princípios SOLID

36

Lei de DemeterDemeter na Prática

Seus parâmetrosQuando o seu método recebe parâmetros, ele pode chamar algummétodo fornecido por este parâmetro diretamente

1 c lass JobPost2 def pos t_u r l ( i d )3 ’ h t t p : / / www. k u n i r i . org / posts / # { i d } ’4 end5 end

Seminário POO | Princípios SOLID

37

Lei de DemeterDemeter na Prática

Qualquer objeto criado ou instanciadoQuando o seu método cria objetos locais, ele pode chamar métodosnos objetos locais

1 c lass Ma i le r2 def prepare_emai ls ( l i s t )3 e m a i l _ s a n i t i z e r = Ema i lSan i t i ze r . new4 e m a i l _ s a n i t i z e r . s a n i t i z e ( l i s t )5 end6 end

Seminário POO | Princípios SOLID

37

Lei de DemeterDemeter na Prática

Qualquer objeto criado ou instanciadoQuando o seu método cria objetos locais, ele pode chamar métodosnos objetos locais

1 c lass Ma i le r2 def prepare_emai ls ( l i s t )3 e m a i l _ s a n i t i z e r = Ema i lSan i t i ze r . new4 e m a i l _ s a n i t i z e r . s a n i t i z e ( l i s t )5 end6 end

Seminário POO | Princípios SOLID

38

Lei de DemeterDemeter na Prática

Seu próprio componente de objetoSeu método pode chamar métodos nos seus próprios camposdiretamente (mas não em campos do campo)

1 c lass Ma i le r2 def i n i t i a l i z e ( ema i l _san i t i ze r , l i s t )3 @emai l_sani t izer = Ema i lSan i t i ze r . new4 @l is t = l i s t5 end67 def prepare_emai ls ( l i s t )8 @emai l_sani t izer . s a n i t i z e ( l i s t )9 end

10 end

Seminário POO | Princípios SOLID

38

Lei de DemeterDemeter na Prática

Seu próprio componente de objetoSeu método pode chamar métodos nos seus próprios camposdiretamente (mas não em campos do campo)

1 c lass Ma i le r2 def i n i t i a l i z e ( ema i l _san i t i ze r , l i s t )3 @emai l_sani t izer = Ema i lSan i t i ze r . new4 @l is t = l i s t5 end67 def prepare_emai ls ( l i s t )8 @emai l_sani t izer . s a n i t i z e ( l i s t )9 end

10 end

Seminário POO | Princípios SOLID

39

Lei de DemeterDemeter na Prática

A si mesmoSeu método pode chamar outros métodos ou atributos na suaprópria classe diretamente

1 c lass Address2 a t t r _ r e a d e r : c i t y , : s t a t e34 def f u l l _a d d ress5 " #{ c i t y } , #{ s t a t e } "6 end7 end

Seminário POO | Princípios SOLID

39

Lei de DemeterDemeter na Prática

A si mesmoSeu método pode chamar outros métodos ou atributos na suaprópria classe diretamente

1 c lass Address2 a t t r _ r e a d e r : c i t y , : s t a t e34 def f u l l _a dd ress5 " #{ c i t y } , #{ s t a t e } "6 end7 end

Seminário POO | Princípios SOLID

40

Lei de DemeterExemplo

12 def sold_brand_emai l ( order )3 @order = order4 mai l (5 to : @order . l i ne_ i t ems . l a s t . brand . designer . email ,6 sub jec t : ’You sold a brand ! ’ )7 end

Seminário POO | Princípios SOLID

40

Lei de DemeterExemplo

12 def sold_brand_emai l ( order )3 @order = order4 mai l (5 to : @order . l i ne_ i t ems . l a s t . brand . designer . email ,6 sub jec t : ’You sold a brand ! ’ )7 end

Seminário POO | Princípios SOLID

41

Lei de DemeterExemplo - Refatorando

1 c lass Ma i le r2 def send_mailer ( order )3 mai l (4 to : order . customer . email ,5 sub jec t : " Thanks f o r purchasing ! " )6 end7 end

Seminário POO | Princípios SOLID

42

Lei de DemeterExemplo - Aplicando a Lei de Demeter

1 c lass Ma i le r2 def send_mailer ( order )3 customer_email = @customer . emai l4 mai l (5 to : order . customer_email ,6 sub jec t : " Thanks f o r purchasing ! " )7 end8 end

Seminário POO | Princípios SOLID

43

Lei de DemeterExemplo - Aplicando a Lei de Demeter

1 c lass Ma i le r2 def send_mailer ( order )3 order . send_mai ler4 end5 end67 c lass Order8 def send_mailer9 mai l (

10 to : @customer . email ,11 sub jec t : " Thanks f o r purchasing ! " )12 end13 end

Seminário POO | Princípios SOLID

44

Bibliografia

I Fox, A.; Patterson, D. Engineering Software as a Service: AnAgile Approach using Cloud Computing. Versão 1.1.1.

I http://rails-bestpractices.com/posts/2010/07/24/the-law-of-demeter/

I https://scotch.io/bar-talk/s-o-l-i-d-the-first-five-principles-of-object-oriented-design

I http://gespinosa.org/2015/law-of-demeter/

Seminário POO | Princípios SOLID

Obrigado pela atenção!