Análise e Projeto Orientados a Objeto com UML e Padrões © Nabor C. Mendonça 2001 1 Da Análise ao Projeto Artefatos de análise capturam os resultados da investigação do domínio do problema Artefato Questões Respondidas Quais são os cenários usuário-sistema? Casos de uso Quais são os conceitos e seus relacionamentos? Modelo conceitual Diagramas de seqüência Quais são as operações do sistema? Contratos O que fazem as operações do sistema? Artefatos de projeto capturam uma solução para o problema baseada no paradigma de OO – Diagramas de colaboração e classe de projeto – Atribuição de responsabilidades e uso de padrões © Nabor C. Mendonça 2001 2 Definindo Diagramas de Colaboração Um Ciclo de Desenvolvimento Refin. Plano © Nabor C. Mendonça 2001 Sinc. Artefatos Análise Notas Projeto Impl. a. em paralelo com diag. interação b. ordem variada Teste 1. Definir Casos de Uso Reais 2. Definir Rel. & IU 4. Definir Diag. Colaboração 5. Definir Diag. Classe 3. Refinar Arquitetura a b 6. Definir Esquema do BD 3 Diagramas de Colaboração Um diagrama de colaboração ilustra as interações de mensagens entre objetos do modelo do domínio (diagrama de classe, simplificado), para realizar uma operação de sistema – Atribuição de responsabilidades aos objetos – Ponto de partida é o cumprimento das póscondições especificadas no contrato da operação Baseado na suposição de que as pré-condições da operação são satisfeitas © Nabor C. Mendonça 2001 4 Diagramas de Colaboração Diagrama de colaboração – Ilustra interações num formato de grafo ou rede message1() :ClassAInstance 1: message2() 2: message3() :ClassBInstance – A mensagem não-numerada (a primeira) é uma operação de sistema – Note que mandar uma mensagem m() para um objeto X corresponde a executar o código X.m(), isto é, invocar o método m() de X © Nabor C. Mendonça 2001 5 Diagramas de Colaboração Exemplo para a operação fazerPagamento, do sistema ProcessarVendas de um supermercado direction of message makePayment(cashTendered) :POST first internal message 1: makePayment(cashTendered) link line 1.1: create(cashTendered) first message :Payment instance © Nabor C. Mendonça 2001 :Sale parameter 6 Como Fazer um Diagrama de Colaboração Regras úteis 1. Criar um diagrama em separado para cada uma das operações de sistema sendo desenvolvidas na iteração corrente - Para cada mensagem de operação de sistema, criar um diagrama com essa mensagem como mensagem inicial 2. Se um diagrama fica muito complexo (não cabe facilmente num folha de papel A4), o diagrama deve ser dividido em diagramas menores 3. Usar as pós-condições dos contratos de operação, e a descrição dos casos de uso para projetar um sistema cujo objetos interagem para cumprir as tarefas exigidas, segundo o modelo do domínio © Nabor C. Mendonça 2001 7 Diagramas de Colaboração e Outros Artefatos Modelo do Domínio Cashier System Operation: enterItem enterItem (upc, quantity) Postconditions: 1. If a new sale, a new Sale has been created... enterItem(upc, qty) :POST endSale() makePayment(amount) Operation: makePayment makePayment (amount) System Sequence Diagram © Nabor C. Mendonça 2001 Postconditions: 1. ... Contracts :POST Collaboration Diagrams 8 Notação Básica Classes e instâncias Sale :Sale class instance s1: Sale named instance Links msg1() :POST 1: makePayment(cashTendered) :Sale link line © Nabor C. Mendonça 2001 9 Notação Básica Mensagens 1: message1() 2: message2() 3: message3() msg1() :POST :Sale all messages flow on the same link Parâmetros parameters msg1() 1: makePayment(amount: Money) :POST © Nabor C. Mendonça 2001 :Sale 10 Notação Básica Valor de retorno return value type msg1() 1: tot := total(): Real :POST :Sale return value name © Nabor C. Mendonça 2001 11 Notação Básica Mensagem para “self” ou “this” msg1() :POST 1: clear() Iteração iteration recurrence values omitted msg1() 1*: li := nextLineItem(): SalesLineItem :POST © Nabor C. Mendonça 2001 :Sale 12 Notação Básica Cláusula de iteração iteration clause msg1() 1*: [i := 1..10] li := nextLineItem(): SalesLineItem :POST :Sale Iteração com múltiplas mensagens msg1() 1*: [i := 1..10] msg2() :A myB :B 2*: [i := 1..10] msg3() myC :C msg1() { for i := 1 to 10 { myB.msg2() myC.msg3() } } note that iteration clauses are equal © Nabor C. Mendonça 2001 13 Notação Básica Criação de instância create message, with optional initializing parameters msg1() 1: create(cashier) :POST :Sale new created instance «new» :Sale "«new»" is optionally allowed for emphasis © Nabor C. Mendonça 2001 14 Notação Básica Seqüenciamento de mensagens not numbered msg1() :ClassA 1: msg2() :ClassB 1.1: msg3() legal numbering © Nabor C. Mendonça 2001 :ClassC 15 Notação Básica Seqüenciamento complexo de mensagens first second third msg1() ;ClassA 1: msg2() :ClassB 1.1: msg3() 2.1: msg5() 2: msg4() fourth :ClassC 2.2: msg6() fifth sixth :ClassD © Nabor C. Mendonça 2001 16 Notação Básica Mensagens condicionais conditional message, with test msg1() 1: [nova venda] create() :TV :Venda 1.1: create() :LinhaDeVenda © Nabor C. Mendonça 2001 17 Notação Básica Caminhos condicionais mutuamente exclusivos unconditional after either msg2 or msg4 :ClassE 1a and 1b are mutually exclusive conditional paths 2: msg6() msg1() 1a: [test1] msg2() :ClassA :ClassB 1b: [not test1] msg4() :ClassD © Nabor C. Mendonça 2001 1b.1: msg5() 1a.1: msg3() :ClassC 18 Notação Básica Operação entrarItem() (diagrama parcial) conditional message, with test entrarItem() 1: [nova venda] create() :TV :Venda 2: [velha venda] criarLinhaDeVenda() 3: create() :LinhaDeVenda Note que mensagens condicionais simulam IF ... THEN ... ELSE © Nabor C. Mendonça 2001 19 Notação Básica Coleções (multiobjects) Sale sales : Sale multiobject Mensagens para uma coleção message sent to the collection object itself msg1() 1: s := size() : int :Sale © Nabor C. Mendonça 2001 SalesLineItem :SalesLineItem 20 Notação Básica Mensagens para uma coleção e um elemento msg1() 1: create() :Sale 2: addElement(sl) sl: SalesLineItem SalesLineItem :SalesLineItem msg1() 2: print() :Sale sl: SalesLineItem 1: sl := get(key) © Nabor C. Mendonça 2001 SalesLineItem :SalesLineItem 21 Responsabilidades e Métodos Responsabilidade é “um contrato ou obrigação de um tipo ou classe” [Booch et al.’97] – Relacionada com o comportamento dos objetos Dois tipos básicos: – De conhecer (alguma coisa) Ex.: dados privados encapsulados, objetos relacionados, informação derivada ou calculada – De fazer (alguma coisa) Ex.: Fazer algo individualmente, iniciar uma ação em outros objetos, controlar ou coordenar atividades em outros objetos © Nabor C. Mendonça 2001 22 Responsabilidades e Métodos Responsabilidade são atribuídas aos objetos do sistema durante o projeto OO – Exemplos: “Uma Venda é responsável por imprimir a si própria” (de fazer) “Uma Venda é responsável por conhecer sua data” (de conhecer) Tradução para classes e métodos influenciada pela granulosidade da responsabilidade – Um único método para “imprimir venda” – Dezenas de métodos para “prover um mecanismo de acesso a SGBD relacionais” © Nabor C. Mendonça 2001 23 Responsabilidades e Métodos Métodos são implementados para cumprir responsabilidades – Podem agir sozinhos ou em colaboração com outros métodos e objetos Exemplo – A classe Venda pode definir um método específico para cumprir a responsabilidade de impressão – Esse método, por sua vez, pode precisar colaborar com outros objetos, possivelmente enviando mensagens de impressão para cada um dos objetos Item-de-Venda associados à Venda © Nabor C. Mendonça 2001 24 Responsabilidades e Diagramas de Interação Diagramas de interação ilustram decisões na atribuição de responsabilidades a objetos – Quais mensagens são enviadas para diferentes classes e objetos? implies Sale objects have a responsibility to print themselves print() 1*: [i:= 1..N]] sli := next() :Sale 2*: [i:=1..N] : print() SalesLineItem :SalesLineItem sli:SalesLineItem Guias práticos para facilitar a tomada de decisões na atribuição de responsabilidades são oferecidos pelos padrões GRASP © Nabor C. Mendonça 2001 25 Padrões Nome e descrição de um problema comum de domínio e sua respectiva solução – Expresso de modo que o padrão possas ser aplicado a novos contextos e circunstâncias variadas Capturam princípios fundamentais de engenharia de software Podem oferecer guias de como responsabilidades devem ser atribuídas a objetos, dada uma categoria específica de problema © Nabor C. Mendonça 2001 26 Padrões Em geral, não contêm novas idéias nem soluções originais – Possuem nomes sugestivos – Codificam soluções existentes comprovadas Suportam fácil incorporação ou abstração do conjunto de conceitos representado pelo padão Facilitam comunicação – Permitem a discussão de um princípio ou conceito complexo através de um único nome © Nabor C. Mendonça 2001 27 Padrões GRASP Princípios gerais para atribuição de responsabilidades a objetos – Cruciais no POO – Parte da criação de diagramas de interação Cinco padrões mais comuns: – Especialista (“Expert”) – Criador (“Creator”) – Alta coesão (“High Cohesion”) – Baixo acoplamento (“Low Coupling”) – Controlador (“Controler”) © Nabor C. Mendonça 2001 28 Padrão Especialista Problema – Solução – Qual é o princípio mais básico pelo qual responsabilidades são atribuídas no POO? Atribuir responsabilidade para o especialista na informação — a classe que tem a informação necessária para cumprir a responsabilidade Exemplo – Quem deve ser responsável por conhecer o total de uma venda? Informação necessária: conhecer todas as instâncias Item-deVenda da Venda e o subtotal de cada uma delas © Nabor C. Mendonça 2001 29 Padrão Especialista Exemplo (cont.) – Pelo padrão, a classe Venda deve ser a responsável t := total() Venda :Venda data tempo Novo método – total() Mas quem dever ser responsável por conhecer o subtotal de um Item-de-Venda? Informação necessária: Item-de-Venda.quantidade e Especificação-Produto.preço © Nabor C. Mendonça 2001 30 Padrão Especialista Exemplo (cont.) – Pelo padrão, a classe Item-de-Venda deve ser a responsável t := total() 1*: [i:=1..N]] sli := next() :Venda Venda data tempo 2*: [i:=1..N] st := subtotal() total() sli:LinhaDeVenda SalesLineItem :LinhaDeVenda LinhaDeVenda quantidade New method – subtotal() Porém, para cumprir essa responsabilidade um Item-de-Venda precisa conhecer o preço do Item © Nabor C. Mendonça 2001 31 Padrão Especialista Exemplo (cont.) – Portanto, o Item-de-Venda deve mandar uma mensagem para a Especificação-Produto para saber o preço do item t := total() 1*: [i:=1..N]] sli := next() :Venda Venda data tempo 2*: [i:=1..N] st := subtotal() total() sli:inhaDeVenda SalesLineItem :LinhaDeVenda LinhaDeVenda quantidade 2.1: p := preco() subtotal() :Especificacao Produto Especificacao Produto descricao preco UPC New method © Nabor C. Mendonça 2001 preco() 32 Padrão Especialista Exemplo (cont.) – Concluindo, para cumprir a responsabilidade de conhecer e comunicar o total da venda, três responsabilidades foram atribuídas a três classes de objetos Classe © Nabor C. Mendonça 2001 Responsabilidade Venda conhece total da venda Item-de-Venda conhece subtotal do item Especificação-Produto conhecer preço do produto 33 Padrão Especialista Benefícios – Mantém encapsulamento (baixo acoplamento) – Comportamento é distribuído através das classes que tem a informação necessária para cumprir a responsabilidade (alta coesão) Também conhecido como – “Quem sabe, faz” – “Faço eu mesmo” – “Cada serviço com seus atributos” © Nabor C. Mendonça 2001 34 Padrão Criador Problema – Quem deve ser responsável por criar uma nova instância de alguma classe? Solução – Atribuir à classe B a responsabilidade de criar uma instância da classe A se: B agrega instâncias de A B contém instâncias de A B registra instâncias de A B usa bem de perto instâncias de A B tem os dados de inicialização para criar instâncias de A (B portanto é um especialista na criação de A) © Nabor C. Mendonça 2001 35 Padrão Criador Exemplo – Quem deve ser responsável por criar uma instância de Item-de-Venda? – Pelo padrão, Venda deve ser responsável. criarLinhaDeVenda(quantidade) Venda :Venda 1: create(quantidade) New method data tempo criarLinhaDeVenda() total() :LinhaDeVenda Benefícios – Suporta baixo acoplamento © Nabor C. Mendonça 2001 36 Padrão Baixo Acoplamento Problema – Solução – Como conseguir menor dependência (entre as classes) e maior reuso? Atribuir a responsabilidade de modo que o acoplamento (dependência entre classes) permaneça baixo Exemplo – Quem deve ser responsável por criar um Pagamento e associá-lo à Venda? – Pelo padrão Criador, poderia ser POST (uma vez que POST “registra” pagamentos no mundo real) © Nabor C. Mendonça 2001 37 Padrão Baixo Acoplamento Exemplo (cont.) fazerPagto() :TV 1: create() p : Pagto 2: addPagto(p) – :Venda Uma solução melhor, (que preserva baixo acoplamento) é a própria Venda criar o Pagamento fazerPagto() :TV 1: fazerPagto() :Venda 1.1. create() :Pagto © Nabor C. Mendonça 2001 38 Padrão Baixo Acoplamento Benefícios – Responsabilidade não é (ou é pouco) afetada por mudanças em outros componentes – Responsabilidade é mais simples de entender isoladamente – Maior chance para reuso © Nabor C. Mendonça 2001 39 Padrão Alta Coesão Problema – Solução – Como manter a complexidade (das classes) em um nível “controlável”? Atribuir a responsabilidade de modo que a coesão (força do relacionamento entre as responsabilidades de uma classe) permaneça alta Exemplo – – Quem deve ser responsável por criar um Pagamento e associá-lo à Venda? Pelo padrão Criador, seria TV. Mas se TV for o responsável pela maioria das operações do sistema, ele vai ficar cada vez mais sobrecarregado e não coeso © Nabor C. Mendonça 2001 40 Padrão Alta Coesão Níveis de coesão – Muito baixa Um classe tem muitas responsabilidades em áreas funcionais bastantes diferentes – Baixa Um classe é responsável por uma tarefa complexa de uma única área funcional – Moderada Um classe tem moderadas responsabilidades em uma única área funcional e colabora com outras classes para cumprir suas tarefas – Alta Um classe tem responsabilidades leves apenas em algumas áreas que estão logicamente relacionadas com o conceito da classe © Nabor C. Mendonça 2001 41 Padrão Alta Coesão Benefícios – Aumento da clareza e compreensão do projeto – Simplificação de manutenção – Baixo acoplamento – Reuso facilitado © Nabor C. Mendonça 2001 42 Padrão Controlador Problema – Quem deve ser responsável por tratar um evento do sistema? Solução – Atribuir a responsabilidade de tratar um evento do sistema para uma classe “controladora” representando: o sistema como um todo (facade controller) o negócio ou organização com um todo (facade controller) uma coisa ou papel de uma pessoa do mundo real envolvida diretamente com a tarefa (role controller) um “tratador” (handler) artificial para todos os eventos de um caso de uso (use-case controller) © Nabor C. Mendonça 2001 43 Padrão Controlador Exemplo – Pelos padrões Baixo Acoplamento e Alta Coesão, a melhor escolha como controlador é POST Sistema terminarVenda() entrarItem() fazerPagto() system operations discovered during system behavior analysis © Nabor C. Mendonça 2001 TV ... terminarVenda() entrarItem() fazerPagto() allocation of system operations during design, using the Controller pattern 44