Documente Academic
Documente Profesional
Documente Cultură
Motivos da Entropia
Qual a substncia mais voltil do mundo ?
Os novos requisitos no so compatveis com o projeto inicial do sistema O projeto deve ser ajustado rapidamente para atender aos requisitos na janela de tempo disponvel Novas dependncias entre mdulos surgem em funo das alteraes rpidas (afetando a estrutura do sistema) Degradando a estrutura, o sistema pode se tornar mais frgil, difcil de alterar e manter
Degradao do Projeto
A busca do clice sagrado
Fomos acostumados a acreditar que somente os maus projetos degradam ao longo do tempo Isto gera uma tendncia de se investir muito tempo nos estgios iniciais de desenvolvimento, buscando o melhor projeto possvel O problema que os melhores projetos tambm possuem entropia, degradando ao longo do tempo
Degradao do Projeto
Possveis solues
Avaliao contnua da estrutura do sistema e re-projeto das partes mais afetadas ao longo do processo Investir continuamente no sentido de manter o projeto simples e flexvel (reduo de dependncias) No deixar o re-projeto para ser feito todo de uma nica vez, pois o sistema continuar a se mover O re-trabalho inevitvel em grande parte dos sistemas, exceto em domnios muito conhecidos. Aceite o re-trabalho! Princpios de projeto ajudam a manter o projeto de um sistema consistente.
Projeto Lgico
Entre o modelo de anlise ...
Classes Atributos Mtodos Cardinalidades Dependncias
Taxa =
ValorCorrente + Re tiradas
Aquisies
CalculaTaxaRetorno CalculaTaxaRetorno CalculaTaxaCompanhia CalculaTaxaCompanhia Aquisies Aquisies Data Data Valor Valor
*
CalculaRetiradas CalculaRetiradas CalculaAquisies CalculaAquisies
CalculaTaxaRetorno CalculaTaxaRetorno CalculaTaxaCompanhia CalculaTaxaCompanhia Aquisies Aquisies Data Data Valor Valor
*
CalculaRetiradas CalculaRetiradas CalculaAquisies CalculaAquisies
Cardinalidades
Consideremos uma associao ou agregao entre duas classes, digamos C1 e C2. Esta associao possui uma cardinalidade em cada classe. Cardinalidade 0:1
A classe possui um atributo indicando o objeto que est na outra ponta da associao Se este atributo contiver o valor nulo, no existe nenhum objeto na outra ponta (cardinalidade 0) Se seu valor for diferente de nulo, ele dever ser a referncia do objeto na outra ponto (cardinalidade 1)
Cardinalidade 1:1
Mesma soluo, sem permitir que o atributo receba valor nulo
Cardinalidades
Cardinalidade 0:N
A classe deve conter uma lista que indique os elementos da outra ponta da associao Se a lista estiver vazia, no teremos nenhum objetos na outra ponta (cardinalidade 0) Caso contrrio, a lista contm as diversas referncias dos outros objetos (cardinalidade N)
Cardinalidade 1:N
Mesma soluo, sem permitir que a lista fique vazia
Cardinalidades
Em suma, no projeto no existe diferena significativa entre as cardinalidades 0:1/1:1 ou entre 0:N/1:N Duas solues para cardinalidade 1:N ou 0:N
Classe herda de uma classe que represente uma lista Classe contm uma classe que represente uma lista
Lista Lista
C1 C1
C1 C1
C2 C2
Lista Lista
C2 C2
Cardinalidades no Exemplo
Extrato Extrato DataEmissao DataEmissao Vector Vector
CalculaTaxaRetorno CalculaTaxaRetorno CalculaTaxaCompanhia CalculaTaxaCompanhia Vector Vector Aquisies Aquisies Data Data Valor Valor
*
CalculaRetiradas CalculaRetiradas CalculaAquisies CalculaAquisies Vector Vector Retiradas Retiradas Data Data Valor Valor
Aplicao de Herana
Extrato Extrato DataEmissao DataEmissao Vector Vector ListaMovimentos ListaMovimentos
2
CalculaSomatrio CalculaSomatrio
*
CalculaRetiradas CalculaRetiradas CalculaAquisies CalculaAquisies
Aquisies Aquisies
Retiradas Retiradas
Dependncias
Uma relao de dependncia ocorre quando uma classe utiliza os servios de outra classe sem estar associada a ela
Suponha que um mtodo de uma classe C1 receba como parmetro um objeto da classe C2 A classe C1 pode utilizar os mtodos do objeto da classe C2 atravs do parmetro. Dizemos que a classe C1 depende da classe C2, pois, caso C2 no existisse, o mtodo de C1 citado acima tambm no poderia existir Observe que isto no significa que a classe C1 est associada classe C2. O parmetro transitrio, enquanto uma associao pode existir ao longo de toda a vida da classe.
Dependncias
Problemas com dependncias
A existncia de uma dependncia entre duas classes ou pacotes implica em uma amarrao entre estes elementos Uma alterao ou um erro em uma classe poder afetar as classes que so dependentes desta Uma classe no pode ser reutilizada sem que as classes de quem ela depende tambm sejam reutilizadas
Dependncias Circulares
Dependncia bidirecional
Ocorrem quando uma classe A depende de uma classe B, que por sua vez depende da classe A A dependncia circular faz com que as duas classes sejam tratadas como uma nica classe Algumas linguagens apresentam dificuldades no tratamento de dependncias circulares Algumas vezes, a dependncia circular pode ser resolvida dividindo-se uma das classes em classes menores
Interfaces
Interface de Entrada
Regras de Negcio
Regras de Negcio
Interface de Sada
Princpios de Projeto OO
Responsabilidade nica Princpio Open-Closed Substituio de Liskov Inverso de dependncias Lei de Demeter
Adaptado de: Structured Analisys and System Specification, Tom de Marco, Yourdon Press, 1979
Retngulo Retngulo Aplicao de Clculo Aplicao de Clculo Geomtrico Geomtrico desenha () desenha () calculaArea () calculaArea () Aplicao Grfica Aplicao Grfica
GUI GUI
GUI GUI
Princpio Open-Closed
Classes devem ser abertas para extenso, mas fechadas para modificao
Quando uma mudana em um sistema resulta em uma cascata de mudanas em mdulos dependentes, o projeto do sistema possui caractersticas indesejveis A cascata de alteraes torna o sistema mais frgil e torna suas partes mais difceis de reutilizar O princpio open-closed sugere que se construam classes que nunca mudem. Quando os requisitos mudarem, o comportamento das classes deve ser estendido pela adio de cdigo novo, no pela alterao do cdigo existente.
Princpio Open-Closed
Projeto baseado em interfaces
Uma forma de atingir o princpio open-closed consiste em basear as dependncias entre classes em interfaces As interfaces definem o protocolo de mtodos necessrios para a comunicao entre as classes Diferentes classes que atendam a interface podem ser utilizadas, cada qual com comportamento distinto
Princpio Open-Closed
Considere um sistema que desenha figuras geomtricas mantidas em uma lista. Temos funes para desenhar as figuras de acordo com seu tipo.
enum ShapeType {circle, square}; struct Shape { ShapeType itsType; }; struct Circle { ShapeType itsType; double itsRadius; Point itsCenter; }; struct Square { ShapeType itsType; double itsSide; Point itsTopLeft; }; typedef struct Shape *ShapePointer; // Funes Externas void DrawSquare(struct Square*) void DrawCircle(struct Circle*); void DrawAllShapes(ShapePointer list[], int n) { int i; for (i=0; i<n; i++) { struct Shape* s = list[i]; switch (s->itsType) { case square: DrawSquare((struct Square*)s); break; case circle: DrawCircle((struct Circle*)s); break; } } }
Princpio Open-Closed
O projeto anterior no atende ao princpio
Uma nova figura geomtrica no pode ser introduzida sem alteraes no mtodo de desenho Funes para outros requisitos, como redimensionar a figura e indicar sua cor, tambm precisariam do switch
Princpio Open-Closed
class Shape { public: virtual void Draw() = 0; }; class Square : public Shape { public: virtual void Draw (); }; class Circle : public Shape { public: virtual void Draw (); }; void DrawAllShapes (Shape *list[], int n) { int i; for (i = 0; i < n; i++) list[i] -> Draw(); } Classe abstrata (interface)
Princpio Open-Closed
Um projeto no pode ser totalmente fechado
O projeto anterior permite que uma nova figura seja includa, mas e se um novo requisito exigisse uma ordem especfica de desenho das figuras? Como o projeto no pode ser totalmente fechado, este deve ser planejado para fechar os requisitos mais importantes Experincia e conhecimento do domnio da aplicao auxiliam o projetista na identificao destes fechamentos
Princpio Open-Closed
Heursticas
Observe os elementos envolvidos no sistema (figuras) Observe as operaes sobre estes elementos (desenho, ...) Observe hierarquias e organizaes naturais Observe as regies de extenso do projeto Estimule mudanas o mais cedo possvel (prottipos)
Barbara Liskov, Data Abstraction and Hierarchies, SIGPLAN Notices, 23/5 (May/1988)
class Shape { public: virtual void Draw() = 0; }; class Square : public Shape { public: virtual void Draw (); }; class Circle : public Shape { public: virtual void Draw (); };
class ShapeList { public: void addShape (Shape *ashape); void removeShape (int index); ... }; void ShapeList::addShape (Shape *ashape); { if (ashape instanceof Square) { // Faa algo especfico para quadrados } // Insero convencional ... }
class Shape { public: virtual int getType () = 0; virtual void Draw() = 0; }; class Square : public Shape { public: virtual int getType () { return 1 }; virtual void Draw (); }; class Circle : public Shape { public: virtual int getType () { return 2 }; virtual void Draw (); };
class ShapeList { public: void addShape (Shape *ashape); void removeShape (int index); ... }; void ShapeList::addShape (Shape *ashape); { if (ashape -> getType () == 1) { // Faa algo especfico para quadrados } // Insero convencional ... }
Um quadrado um retngulo ?
class Rectangle { private: int height, width; public: void setHeight (int aheight); void setWidth (int awidth); int setHeight (); int setWidth (); virtual void Draw (); }; class Square : public Rectangle { public: virtual void Draw (); };
Em termos de dados, um quadrado pode ser representado como um retngulo, mas o comportamento das duas classes distinto ! Por exemplo, chamar o mtodo herdado setHeight() para o quadrado pode transform-lo em algo que no mais quadrado. Isto pode provocar problemas com testes e assertivas. Revise heranas com esta caracterstica (distines comportamentais).
class CartaBaralho { public boolean Compara (CartaBaralho c) { ... } }; class Ordenador { public void ordena (CartaBaralho[] cartas) { // Implementao do algoritmo de quicksort ! } };
Assim ...
Um bom projeto deveria evitar estas repeties definindo um conceito genrico, que seria especializado pelos objetos de interesse do sistema e utilizado pelo algoritmo Este o princpio da inverso de dependncias !!!
Lei de Demeter
A probabilidade de uma classe parar de funcionar depende do nmero de classes com quem ela se comunica
A idia geral que se uma classe depende de diversas outras classes, ela poder parar de funcionar quando qualquer destas classes apresentar um problema Esta uma das razes pela qual devemos reduzir o nmero de classes de quem uma classe depende
A Lei de Demeter determina que um objeto somente deveria chamar mtodos ...
Da prpria classe De objetos armazenados diretamente em seus atributos De objetos recebidos como parmetros De objetos criados dentro de seus mtodos
Lei de Demeter
Finalidade
A Lei de Demeter evita longas cadeias de chamadas entre diferentes classes para cumprir uma nica funo O cumprimento da funo deveria se desencadear pela interao entre os objetos destas classes O preo da aplicao da Lei de Demeter o crescimento no nmero de mtodos oferecidos por cada classe Sua principal vantagem est na reduo da complexidade da realizao de um conjunto de tarefas
Em suma ...
Fale apenas com seus vizinhos
Lei de Demeter
Cdigo que no segue a Lei de Demeter ...
public void ligaTelevisao (Televisao televisao) { televisao.painel.Botoes.botao_principal.liga (); } Televisao Televisao
Painel Painel
Botoes Botoes
Lei de Demeter
Cdigo que segue a Lei de Demeter ...
... televisao.Liga (); ... public Televisao::Liga () { painel.Liga (); } public Painel::Liga () { botoes.botao_principal.liga (); } public Botoes::Liga () { botao_principal.liga (); } public Botao::Liga () { ... // Cdigo que liga o boto } Televisao Televisao Liga () Liga ()
Lei de Demeter
Sem a Lei de Demeter Televisao Televisao get () get () get () liga () Painel Painel Botoes Botoes Botao_Principal Botao_Principal
Seguindo a Lei de Demeter Televisao Televisao liga () liga () liga () Painel Painel Botoes Botoes Botao_Principal Botao_Principal