Identificação de métodos e mensagens Após a leitura desse capítulo, o leitor saberá: - Modelar um método. - identificar a diferença de método e mensagem - identificar os componentes de um diagrama de seqüência - Identificar a seqüência de métodos - Identificar os três tipos de visibilidade de atributos e como representá-los - Identificar uma característica de sincronismo de métodos - Identificar uma característica de um método assíncrono - Identificar quando e como um método deve criar um objeto. Livro Título: UML Essencial - Um Breve Guia para a Linguagem-Padrão de Modelagem de Objeto Nome do autor: Martin Fowler Editora: Artmed Ano: 2005 Edição: 3º Capítulo: capítulo 4: casos de Título: Utilizando UML e Padrões Uma Introdução à Análise e ao Projeto Orientado a Objetos e ao Processo Unificado Nome do autor: Craig Larman Editora: Artmed - rever Ano: 2007 Edição: 3º
No fim desta aula você: Aprendeu o que é encapsula mento Aprendeu o que é um método e como modelá-lo Aprendeu a diferença entre método síncrono e método assíncrono Aprendeu sobre a visibilidade de atributos Aprendeu sobre as características de um diagrama de seqüência Aprendeu a definir uma classe de projeto.
EXERCÍCIOS 1 um diagrama de interação serve para: A mostrar o fluxo de informação entre o ator e o sistema B mostra como as mensagens retornam para o ator C - mostra a seqüência de chamada de métodos D mostra a seqüência de instancias de objetos graficamente E mostar como o fluxo de informação deve ser armazenado 2 A linha da vida serve para : A definir o sincronismo entre a criação de objetos B representar o tempo de vida de um objeto C representa o tempo de vida de uma classe D representa o tempo de vida de um método assíncrono E representa o tempo de vida de um método síncrono 3 o método: 2.1.2 a [sexo = m ] : string:nome,int:numero := MSG(int:CPF) Significa: A o método é etiquetado, portanto deverá ser criado um fluxo de informação contendo nome e numero B o método esta etiquetado, mas não esta correta na sua sintaxe,pois falta a indicação de sexo = f. C é uma mensagem que indica que a classe MSG deverá apresentar os dados de nome e número quando se passa r o CPF. D é um fluxo que é chamado de 2.1 se o sexo = m e apresenta na tela o nome de quem possui o CPF informado E é um método etiquetado que retorna o nome e matricula quando for chamado para um CPF
EXERCÍCIOS 4 considere o diagrama para as afirmações abaixo. Indique a opção que está totalmente correta. A - existe uma função construtora que instancia um objeto de cada participante do diagrama. B Cada objeto tem a sua função construtora que a cria quando é instanciado C- O kill indica qual a função construtora do objeto foi retirada da memória neste momento c o método 1.2.a e 1.2.b são dois métodos assíncronos e que são disparados neste momento d o método ativar é comum aos dois objetos aluno e professor, por isto podemos encapsulá-lo e usuário Exercício 1 Imagine que esteja sendo implantado um sistema de acompanhamento de comunidades carentes, de modo a poder identificar os perfis de cada comunidade, suas demandas e as possibilidades de atuação junto a cada uma. Abaixo são apresentadas algumas classes desse sistema e seus respectivos relacionamentos.
Residência Endereço AreaConst ruida ImovelPro prio Comunidade NomeComuni dade Morador Nome DataNasc Peso Altura Município NomeMunicipi o a) Faça o diagrama de seqüência referente ao método AreaMediaConstruida(), que retorna, para um município, a área média das residências que possuam pelo menos um morador com idade maior do que 70 anos. b) Faça o diagrama de seqüência do método CriancasEstaturaPequena (idade, altura), que retorna o número de crianças da comunidade com idade igual ao argumento idade e estatura inferior ao argumento altura. c) A partir das questões a e b, complemente o diagrama acima apresentando os métodos, navegabilidade e relacionamentos de dependência - diagrama de classes de projeto. Título Diagrama de seqüência Os casos e uso devem ser implementados, deve-se definir como devem ser implementados. Os diagramas de interação, que mostram como as classes interagem, são o diagrama de seqüência e o diagrama de colaboração. Nesta aula vamos estudar os principais aspectos do diagrama de seqüência No diagrama de seqüência estamos definindo que funções devem ser implementadas, se definir como é o código, para que o caso e uso possa ser realizado. O objetivo é identificar funções, que são as unidades para definir novas funções. Comparando com fatoração de números, no diagrama de seqüência fatoramos os caso e uso. Não confunda Um diagrama de
seqüência mostra a seqüência de execução de funções, portanto, não mostra troca de informação. Um diagrama de seqüência é uma espécie de algoritmo de alto nível em que se destaca a chamada das funções. TITULO Uma classe de projeto Uma Classe de projeto é derivada da classe de domínio Na classe de domínio identificamos conjuntos do mundo real, é uma abstração de coisas do mundo real. Uma classe de projeto é código. Quando falamos em classes de projeto estamos preocupados em definir o código capaz de implementar a classe de domínio, nos seus diversos aspectos. O UML considera que uma classe será implementada por isto na sua representação de classe já tem um local para colocarmos os métodos da classe (funções). Quando estamos modelando com a visão de modelagem de domínio deve-se representar na classe apenas o nome da classe e os atributos. O método deve ficar para o momento que vamos fazer o modelo de projeto. Métodos: Um método é uma função que colocamos dentro da classe, isto quer dizer que a função está encapsulada e só pode ser executada a partir da classe. ALUNO NOME MATRICULA TELEFONE INCLUIR(); TRANSFERIR(); AVALIAR(); TRANCAR(); FUNÇÕES ENCAPSULADAS NA CLASSE. TAMBÉM SE DIZ QUE SÃO OS SERVIÇOS QUE A Não é uma boa prática de modelagem se colocar métodos nas classes sem o desenvolvimento de um dos diagramas de interação. Mensagem:
Os objetos precisam trabalhar de forma coordenada, e por isto devem se comunicar através de seus métodos. Um objeto pode chamara a execução de um método de outro objeto. A chamada do método de outra mensagem é o que chamamos de mensagem. Quando desejamos definir como e quais mensagens são transmitidas podemos fazer um diagrama de seqüência ou um diagrama de colaboração são chamados de diagramas interativos. Para cada caso e uso desenhamos que classes e que mensagens são necessárias para se implementar o caso e uso. Diagrama de seqüência: Mostra a seqüência de chamada de métodos (MENSAGENS) ao longo do tempo. Para isto devemos instanciar os objetos que irão ser utilizados. Para se representar um objeto instanciado, por exemplo para a classe aluno, temos: : aluno representa que um objeto qualquer da classe aluno foi instanciado Joao : aluno representa que o objeto nomeado como João da classe aluno foi instanciado. Um objeto instanciado tem um tempo de existência A existência do objeto é representado por um retângulo desenhado em um traço na horizontal chamado linha da vida (representação no tempo).
Na figura o inicio do retângulo indica o momento que o objeto é criado. Uma classe tem no mínimo dois métodos obrigatórios. O método construtor() e o método destrutor(). O método construtor e disponibilizado automaticamente e tem como objetivo criar todas as estruturas de dados, mecanismos de software e controles necessários a existência do objeto. Assim o inicio do retângulo indica que foi executada o método construtor da classe. O método destrutor é responsável por liberar aéreas de trabalho e estruturas que foram estabelecidas pelo construtor Assim o destrutor libera espaço na memória e dispensa a CPU de executar atividades desnecessárias. Quando não se deseja mais o objeto instanciado deve-se passar a função destrutora, normalmente indica-se isto pela palavra DESTROY ou KILL ou FREE. Quando não se indica a chamadas da função destrutora assumese que ela ocorre no final da execução do caso e uso. Um método (ou função encapsulada) é da forma: <tipo:retorno> nome (<parâmetros tipo:nome>); exemplo: int:matricula ID_ALUNO (string:cpf); indica uma função chamada ID_ALUNO que retorna um número inteiro chamado matricula e que ao ser chamada para executar recebe uma string chamada CPF.
Uma boa prática de desenvolvimento é se numerar a seqüência das chamadas de métodos. Embora o UML especifique como se deve representar um método, algumas pessoas não representam os tipos junto ao retorno e aos parâmetros Alguns métodos não precisam de parâmetros Os retornos das funções pode ser representados por linhas pontilhadas. Só tem sentido se colocar retornos quando a informação voltada será usada no processamento de um método. autodelegação Um método pode ser chamado por outro método dentro de uma classe. Neste caso o objeto esta enviando uma mensagem para ele mesmo. È o chamamos de auto delegação e representa-se.
Na prática as linguagens de programação ao executarem um método guardam o endereço desta execução em uma variável especial chamada THIS. Quando se faz à auto delegação busca-se para execução do método o endereço armazenado nesta variável. Podemos indicar a execução da forma: THIS.mesagem(); Uma mensagem é uma chamada a este método. Pode-se indicar o acesso a um atribulo ou método de um objeto indicando o nome do objeto. Assim para a classe: ALUNO NOME MATRICULA TELEFONE FUNÇÕES ENCAPSULADAS NA CLASSE. TAMBÉM SE DIZ QUE SÃO OS SERVIÇOS QUE A CLASSE OFEREÇE INCLUIR(); TRANSFERIR(); AVALIAR(); TRANCAR();
podemos chamar a função construtora, que vai criar o objeto. Suponha que desejamos o objeto João. As linguagens geralmente fazem isto por um método com o mesmo nome da função ou pelo operador new. Aluno João; /aluno é um novo tipo e foi criado o objeto João. Joao = new aluno; / João é um objeto que foi criado da classe aluno. Pode-se acessar os atributos da classe indicando o objeto e a estrutura que desejamos de dentro da classe. Nome --> indica que estamos acessando a variável nome do objeto João Joao.Telefone = 23657854. --> indica que o telefone 23657854 foi atribuído a variável telefone no objeto João. Joao.transferir(); --> indica que foi ativada (executar) a função transferir a partir do objeto João e com as características existentes no objeto na hora da chamada. Vamos construir alguns diagramas de seqüência para explicitar alguns conceitos: Considere o caso e uso: Matricular um aluno em uma universidade. Com uma única classe.
Para incluir um objeto aluno temos o seguinte diagrama de seqüência: inicialmente registram se os objetos que serão usados com a representação de sua existência na linha da vida. Depois começamos a desenhar cada método com as respectivas mensagens. Observe que o nome do caso e uso é o método inicial no diagrama. E este método estabelece uma série de mensagens. Todas as mensagens são feitas no próprio objeto. A primeira mensagem chama o método mostrar_tela(); este método é responsável por criar uma tela para ser preenchida com os dados do aluno e também faz a critica destes dados (eu estou definindo isto), ao se clicar O.K. (eu estou imaginando um botão de O.K. Na tela) os dados (nome, matricula e telefone, correspondente aos atributos da classe, serão conhecidos e devem ser incluídos no conjunto (arquivos ou banco de dados, não é momento de definir isto agora), para isto vou estipular outro método com o nome de incluir_aluno(); e vou passar estes dados como parâmetros. O diagrama de seqüência com os métodos e mensagens fica. Com as informações do diagrama podemos completar a classe aluno, colocando os métodos que identificamos.
Observação: Observe que a chamada de métodos (mensagens)só pode ser feita para métodos definidos na classe, por isto vamos colocando os métodos identificados por cada classe. Se analisarmos a estrutura do caso e uso do exercício verificamos que a forma que foi projetado não é adequada, pois permitirá que se inclua duplicatas de alunos. O ideal é que verificássemos se o aluno já existe no conjunto. Neste caso deveríamos colocar um método para verificar isto, podíamos por exemplo criar um método que retorne a string sim se ele já existe ou não se ele não existe. Só vamos incluir se voltar não. Nosso diagrama então fica:
Veja que o digrama de seqüência serve para verificar a melhor forma de implementar. Por isto durante o estudo e definição de que métodos vamos definir podemos fazer vários diagramas até decidirmos pelo mais adequado. Se tivermos uma linguagem de programação orientada a objetos teríamos de definir nossa classe assim: Classe Aluno { atributos: String Nome; String end; Int matricula; Métodos: Void matricular(); Void mostrar_tela(); String Validar(); Void incluir_aluno(); } O diagrama acima corresponde a um algoritmo que incida métodos usados: Vamos mostrar com uma pseudolinguagem como ficaria o método matricular(); Aluno:: void matricular() { string variável; // para receber a volta da validação
... // nome, end, matricula são variáveis da classe e são //acessadas pelos métodos This.mostrar_tela(); // esta função Le e armazena dados nos atributos; Variável= this.validar(); //retorna sim ou não para a variável Se (variável== não ) This.incluir_aluno() Senão Imprimir aluno já existe retornar } Exemplo 2: Considere que o analista de requisitos nos enviou o seguinte: Os Objetos envolvidos para se realizar o método são: :matricula, :aluno e :curso Estes objetos precisam estar na memória (pelo menos achamos isto inicialmente) par podermos executar as funções (que vamos identificar) e acessar os valores dos atributos. Observe no meu diagrama que comecei pelo objeto matricula, você pode contestar isto. Para fazermos a matricula, no diagrama de classes vemos que precisamos de alguma forma buscar o código do aluno e o código da disciplina,
então mandamos mensagens para estes objetos retornarem estes códigos. Com o conhecimento dos códigos podemos incluir no conjunto associativo. A partir deste diagrama podemos definir as classes: Classe curso Classe aluno Classe matricula {atributo: {atributo: {atributo: String nome; String nome, Int end; cod_curso; Int cod_aluno; Métodos: Int ID_curso(); Métodos: {} Int ID_al(); Métodos: } String nome, end; Int cod_aluno, cod_curso; Void mat(); Void incluir();
A titulo de exemplo teríamos o algoritmo em pseudocódigo correspondente ao diagrama de classes, par ao método mat(): Matricula:: void mat() { int valor1, valor2 // duas variáveis para receber o retorno // dos métodos AL = new aluno; // criou o objeto aluno CUR = new curso; // criou o objeto curso // não precisa criar o objeto matricula, pois ele está na //variável THIS o método deve ser chamada pelo objeto // matricula.. Valor1=AL.ID_al(); Valor2=cur.Id_cur();... This.incluir();... retorna } Atenção: Decidir em que classe colocar um método é uma dúvida comum. Devese estudar a melhor forma de se projetar o método. Deve-se considerar volumes, desempenho, segurança e outros aspectos físicos de implementação. Existe um padrão de projeto chamado padrão do especialista. Um padrão (uma solução já estudada e adaptada) é uma solução que deve ser usada e nos ajuda a dar soluções ótimas para o projeto. O padrão do especialista diz: O método deve ser colocado na classe que conhece (ou deve conhecer)a informação. O uso deste padrão resolve mais de 90% de nossas dúvidas, por onde começar. No exemplo iniciei pelo objeto matricula, pois ele deve ser o detentor da informação dos alunos matriculados. Antigamente, usava-se um cartão de responsabilidade da classe (CRC) neste cartão, à medida que se projetava os métodos, ia-se colocando em que classes estes métodos seriam implementados. Quando um
método é colocado em uma classe dizemos que é responsabilidade dela fornecer o método. Atenção: Padrão do especialista: A responsabilidade do método é da classe que detém a informação Atenção: Cartão de responsabilidade da classe - CRC Documento para registrar os métodos de cada classe EXEMPLO 3: Existem situações que o diagrama de seqüência tem um a condicional. Isto é representado representando-se por letra e com a condição. Vamos considerar o caso e uso e o respectivo diagrama de classe Vamos projetar o diagrama de seqüência para o caso e uso, e verificamos que após se verificar o tipo de usuário (professor ou aluno) deve-se abrir ativar a tela de professor ou de usuário. Assim considerando os objetos envolvidos temos:
Observe a numeração dos métodos. O método logar é 1. E ele é constituídos por chamadas a outros métodos 1.1 (auto método) e 1.2.a que é uma alternativa e 1.2.b outra alternativa. Observe que as alternativas são representadas de um mesmo ponto. O caminho de cada alternativa é indicada pelo valor da condição, por exemplo, 1.2.1[tipo=aluno] indica que será executado o método ativar() da sub classe aluno. No desenvolvimento de um método o ponto onde se define uma chamada pode corresponder a um comando Se... então, ou a um comando switch case. Veja a representação abaixo:
dica A representação numérica indicando níveis, exemplo 1.2, significa o método dois dentro do método um, facilita o desenvolvimento, pois podemos resolver um nível de cada vez, sem nos preocuparmos no nível inferior. O método 1.2.2b.1 que é um método chamado na opção b de método 1.2.2b, que foi selecionado no método 1.2 que é o segundo método a ser executado quando se executa o método 1 Exemplo4: Existem situações que se precisa usar a repetição de chamada de métodos. Suponha o diagrama de caso e com o respectivo diagrama de classes:
Para se fazer o diagrama de seqüência deve-se saber que a nota fiscal, deve ter o nome do cliente, endereço. Deve ter o número da nota e listar todos os itens que compõem a nota. Cada item de nota tem a descrição e o preço unitário do produto. Mas enquanto houver itens de nota fiscal deve-se buscá-los e para cada item buscar as informações do produto; Veja o diagrama abaixo. O quadrado pontilhado mostrar o que deve ser repetido para cada item: A condição assinalada no canto do quadrado delimitador pode ser da forma: Condição booleana: [ x<30 ]
Indicação de variações de uma variável: [ i=1,3,5,7,9,12] Indicação de uma condição [enquanto houver elementos] Mensagens etiquetadas: Já vimos nos itens anteriores o que UML classifica como uma mensagem etiquetada. Uma mensagem etiqueta é quando se estabelece uma série de condições que devem ser cumpridas para se enviar a mensagem De acordo com a UML a sintaxe da etiqueta é: <Predecessor><condição><expressão><retorno> := <mensagem> (<parâmetros>); <predecessor> é uma lista de números separada por vírgulas terminando por uma / Exemplo: 1.1, 1.2, 1.2.1, 1.2.2, 1.2.2.3/ <CONDIÇÃO> <EXPRESSAO> É uma lista de termos de seqüência separados por. seguida por dois pontos. Exemplo 1: 3.1 [x<y] : variável:= função (valor1,valor2); Exemplo 2: 1.1b,1.1 c [x<10] : variável := função (valor1,valor2); - Indica que serão executas as mensagens consecutivamente <Retorno> uma lista de nomes separados por vírgula que são retornados pela função. Exemplo3: 3.1 * [x=1..n] : nome,endereço,matricula:= id_aluno(); Obs: * indica repetição - para valores de x de 1 ate n. Exemplo4: 3.1 * [x=1;x<100,x++] : nome,end := id_al (); Obs: pode-se usar estruturas de sintaxe de linguagens de programação. Exemplo5 : 3.1 * [x=1; x<100,x ++] : nome,end id_al(); Obs: o símbolo * indica que as mensagens podem executar em paralelo, isto é, não existe sincronismo na execução. <Mensagem> é o nome da função. <parâmetros> é o conjunto de parâmetros passados na função pode-se usar sintaxe de alguma linguagem como por exemplos passar simplesmente o nome dos parâmetros: 1.2 : int nome:= Id_aluno (matricula, curso)
Ou passar o tipo junto ao parâmetro: 1.2 : int nome:= id_aluno (string:matricula, int:curso); Casos especiais de representação Tempo real: Um sistema em tempo real, em principio, tem o tempo como o principal fator para sua execução. O sistema precisa responder conforme projetado, permitindo a execução simultânea de processos em paralelo. Precisa-se definir tempo de resposta, comportamento, comunicação entre processos. Embedded System: Um sistema de tempo real, normalmente, tem os processos muito integrados a dispositivos de hardware. Este tipo de sistema é chamado de Embedded System. Classe ativa: Normalmente os objetos (de uma classe passiva) só são instanciados quando recebem mensagens as classes que vimos nos exemplos anteriores-. Uma objeto de uma classe ativa pode tomar iniciativa para executar ações sem enviar mensagens. Para isto deve-se representar os métodos com a preocupação de definir a forma de comunicação entre os objetos ativos e sua sincronização. Na UML uma classe ativa é representado com a indicação do estereótipos <<classe ativa>>. A UML indica a forma de sincronismo durante a transferência das mensagens, por variações na ponta da flecha: I Ponta de flecha sólida: Indica que a chamada do procedimento é síncrono. Indica que a seqüência aninhada (níveis) é toda completada antes da seqüência acionadora. Isto indica que métodos no mesmo nível devem esperar. O remetente da mensagem esperará pelo destinatário esperará a conclusão do método antes de continuar o seu processamento. II Ponta de flecha fina: Fluxo de controle assíncrono. Mostra que o controle é passado sem haver preocupação com a comunicação., também se indica o retorno com a flecha do voltando do objeto solicitado para o solicitante.
III Meia ponta: Indica que o remetente envia a mensagem e continua imediatamente o seu processamento sem esperar pelo destinatário. Iv Mensagem de Intervalo: Uma transação Indica que o remetente esperará pelo destinatário por um período fixo de tempo antes de interromper o processo de transmissão da mensagem e continuar o seu processamento. Exemplo de mensagem assíncrona: figura do livro Modelagem de Objetos Furlan,Jose,David
Observação: Uma ativação é a execução de uma ação. V - Método criar() Pode-se indicar a criação de um objeto na forma Exemplo de diagrama de seqüência: figura do livro Modelagem de Objetos Furlan,Jose,David
Um diagrama de seqüência, usando todas as representações da UML, dá para o implementador uma série de informações importantes. Quando o diagrama de seqüência envolve vários objetos, pode-se ter dificuldade de visualizar o método que se está desenhando. Para resolver isto temos outro tipo de diagrama chamado diagrama de colaboração. O diagrama de colaboração tem o mesmo objetivo do diagrama de seqüência, mas permite uma melhor visualização, pois só se representa as classes envolvidas no método. Dica: Seja simples: 1 - Não queira iniciar usando todas as representações apresentadas nesta aula. Use as básicas e à medida que for ganhando experiência vá introduzindo novas representações 2 O diagrama de seqüência é para ser simples. Por isto desenhe apenas o desenvolvimento de um método ou caso e uso completo por diagrama. Não resolva vários caso-uso ou método no mesmo diagrama 3 pratique, este é o segredo. Lembre-se que ao desenhar um diagrama de seqüência você esta definindo código.