Tarefa: Design de Caso de Uso
Esta tarefa define como refinar os produtos da Análise de Casos de Uso, desenvolvendo Realizações de Casos de Uso no nível de Design.
Disciplinas: Análise e Design
Objetivo
  • Refinar as realizações de casos de uso em termos de interações
  • Refinar os requisitos nas operações de classes de design
  • Refinar os requisitos nas operações de subsistemas de design e/ou suas interfaces
  • Refinar os requisitos nas operações de cápsulas.
Relacionamentos
Descrição Principal

O comportamento de um sistema pode ser descrito utilizando várias técnicas - colaborações ou interações. Esta tarefa descreve o uso de interações, especificamente diagramas de seqüência, para descrever o comportamento do sistema. Os diagramas de seqüência são mais úteis quando o comportamento do sistema ou do subsistema puder ser descrito basicamente pelo serviço de mensagens síncronas. O sistema de mensagens assíncronas, principalmente em sistemas controlados por eventos, é muitas vezes descrito mais facilmente em termos de máquinas de estado e colaborações, o que permite definir possíveis interações entre objetos de maneira compacta. Mensagens assíncronas desempenham uma importante função em tempo real ou em sistemas reativos e são utilizadas para a comunicação entre as instâncias de Produto de Trabalho: Cápsula.

 Representação da UML 1.x

É possível utilizar uma classe proxy para representar o subsistema em diagramas de seqüência. Essa classe está contida no subsistema e é usada para representar o subsistema em diagramas que não suportam o uso direto de pacotes e subsistemas como elementos comportamentais. Utilize a classe proxy nos casos em que deseja mostrar que um subsistema específico responde a uma mensagem. Nesse caso, é possível mostrar as mensagens que estão sendo enviadas do proxy do subsistema para outros objetos.

Consulte Diferenças entre a UML 1.x e a UML 2.0para obter informações adicionais.

Etapas
Criar Realizações de Casos de Uso

O Produto de Trabalho:Projetar Realização de Casos de Uso fornece uma maneira de rastrear o comportamento do Modelo de Design no Modelo de Casos de Uso e organiza as colaborações no Modelo de Design com base no conceito de Caso de Uso.

Crie uma Realização de Casos de Uso de Design no Modelo de Design para cada Caso de Uso a ser projetado. O nome da Realização de Casos de Uso de Design deve ser o mesmo do Caso de Uso associado e uma relação de "realizações" deve ser estabelecida, da realização de casos de uso para seu caso de uso associado.

Descrever Interações entre Objetos de Design

Para cada realização de casos de uso, ilustre as interações entre seus objetos de design participantes, criando um ou mais diagramas de seqüência. As versões anteriores desses diagramas podem ter sido criadas durante a Tarefa: Análise de Casos de Uso.  Tais "versões de análise" das realizações de casos de uso descrevem interações entre as classes de análise.  Elas devem ser desenvolvidas para descrever interações entre elementos de design.

A atualização dos diagramas de seqüência envolve os seguintes passos:

  • Identificar cada objeto que participa do fluxo do caso de uso. Isso é feito ao instanciar classes e subsistemas de design identificados na Tarefa: Identificar Elementos de Design. Em sistemas de tempo real, você também identificará as instâncias de cápsula que participam do fluxo do caso de uso.
  • Represente cada objeto participante em um diagrama de seqüência. Faça uma linha de vida para cada objeto participante no diagrama de seqüência. Para representar os subsistemas de design, existem algumas opções:
    • É possível mostrar as instâncias do subsistema no diagrama de seqüências.
    • É possível utilizar as interfaces realizadas pelo subsistema. Essa é a forma preferencial nos casos em que se deseja mostrar que qualquer elemento de modelo que realiza a mesma interface pode ser utilizado no lugar da interface. Se optar por mostrar as interfaces no diagrama de seqüência, certifique-se de que nenhuma mensagem seja enviada da interface para outros objetos. O motivo disso é que as interfaces encapsulam completamente a realização interna de suas operações. Portanto, não se pode ter certeza de que todos os elementos de modelo que realizam a interface serão projetados de fato da mesma maneira. Portanto, nos diagramas de seqüência, nenhuma mensagem deve ser mostrada sendo enviada das interfaces.
    • É possível utilizar o componente para representar o subsistema nos diagramas de seqüência. Utilize o componente nos casos em que deseja mostrar que um subsistema específico responde a uma mensagem. Nesse caso, é possível mostrar as mensagens que estão sendo enviadas do componente para outros objetos.

    Observe que esses são os diagramas de seqüência no nível do sistema que mostram como interagem as instâncias dos elementos de design de nível superior (normalmente, subsistemas e interfaces de subsistemas). Diagramas de seqüência mostrando o design interno de subsistemas são produzidos separadamente, como parte da Tarefa: Design de Subsistema.

  • Observe que as interações de um objeto ativo são normalmente descritas usando colaborações de especificação e máquinas de estado. Elas seriam utilizadas aqui para mostrar como as mensagens podem ser enviadas para ativar objetos por outros elementos do sistema em uma realização de caso de uso maior. No uso típico, os objetos ativos são encapsulados dentro de subsistemas, para a finalidade desta tarefa, de modo que a realização de casos de uso consista em um conjunto de subsistemas em interação. As interações definem as responsabilidades e interfaces dos subsistemas. Dentro dos subsistemas, os objetos ativos representam encadeamentos simultâneos de execução. Os subsistemas permitem que o trabalho seja dividido entre as equipes de desenvolvimento, com as interfaces servindo como contratos formais entre as equipes. Para sistemas de tempo real, você utilizará o Produto de Trabalho: Cápsulas, para representar os objetos ativos.

    Uma nota secundária sobre a exibição das mensagens provenientes dos subsistemas: a restrição de mensagens somente a interfaces reduz o acoplamento entre elementos de modelo e aprimora a resiliência do design. Sempre que possível, tente fazer isso e, quando houver mensagens dos subsistemas para elementos do modelo que não sejam da interface, procure oportunidades para alterá-las para mensagens para interfaces a fim de melhorar o desacoplamento no modelo.

  • Represente a interação que ocorre com agentes. Represente cada instância de agente e objeto externo com os quais os objetos participantes interagem por uma linha de vida no diagrama de seqüência.
  • Ilustre a mensagem enviada entre os objetos participantes. O fluxo de eventos inicia no topo do diagrama e continua na ordem descendente, indicando um eixo cronológico vertical. Ilustre a mensagem enviada entre os objetos, criando mensagens (setas) entre as linhas de vida. O nome de uma mensagem deve ser o nome da operação disparada pela mensagem. Nos estágios iniciais do design, poucas operações serão designadas aos objetos, por isso talvez você tenha de deixar de fora essas informações e dar à mensagem um nome temporário; tais mensagens são chamadas de "não designadas." Posteriormente, quando tiver descoberto mais a respeito das operações dos objetos participantes, atualize o diagrama de seqüências, "designando" as mensagens com essas operações.
  • Descreva a ação de um objeto ao receber uma mensagem. Isso é feito anexando um script à mensagem correspondente. Coloque esses scripts na margem do diagrama. Use um texto estruturado ou um pseudocódigo. Se você usar um pseudocódigo, certifique-se de que tenha usado construções na linguagem de implementação para facilitar a implementação das operações correspondentes. Quando a pessoa responsável pela classe de um objeto atribuir e definir suas operações, os scripts do objeto fornecerão uma base para esse trabalho.

Diagrama descrito no texto associado.

Documentação do comportamento de caso de uso executado pelos objetos em um diagrama de seqüência.

Quando tiver distribuído o comportamento entre os objetos, considere como o fluxo será controlado. Você localizou os objetos presumindo que eles interagiriam de uma certa maneira na realização de casos de uso e teriam uma determinada função. Ao distribuir o comportamento, você pode começar a testar essas suposições. Em algumas partes do fluxo, pode ser preferível utilizar uma estrutura descentralizada; em outras, prefira uma estrutura centralizada. Para obter as definições dessas variantes e as recomendações sobre quando utilizar os dois tipos de estrutura, consulte Técnica: Diagramas de Seqüência.

Você poderá precisar de novos objetos nesse ponto, por exemplo, se estiver utilizando uma estrutura centralizada e precisar de um novo objeto para controlar o fluxo. Lembre-se de que qualquer objeto adicionado ao modelo de design deve atender aos requisitos feitos em relação do modelo de objeto.

Incorporar Mecanismos de Design Aplicáveis

Durante a Tarefa: Análise Arquitetural, mecanismos de análise foram identificados.  Durante a Tarefa: Identificar Mecanismos de Design, mecanismos de análise são refinados em mecanismos de design, o mapeamento dos mecanismos de análise para os mecanismos de design são capturados no Documento de Arquitetura de Software e os mecanismos de design são documentados nas Diretrizes Específicas do Projeto.  

Durante essa tarefa, Design de Caso de Uso, todos os mecanismos de design aplicáveis são incorporados nas realizações de casos de uso.  O designer pesquisa os mecanismos de design disponíveis e determina aqueles que se aplicam à realização de casos de uso que está sendo desenvolvida, trabalhando dentro das recomendações e diretrizes documentadas no Documento de Arquitetura de Software e nas Diretrizes de Design.  
Nota: O mecanismo de design aplicável pode ter sido identificado na Tarefa: Análise de Casos de Uso, durante a qual as classes de análise podem ter sido "marcadas" com um mecanismo de análise específico, indicando que uma determinada parte da funcionalidade precisou ser manipulada no design.   Em tal caso, os mecanismos de design aplicáveis são aqueles associados aos mecanismos de análise com os quais foram marcadas as classes de análise que participam da realização de casos de uso

O Designer incorpora os mecanismos de design aplicáveis nas realizações de casos de uso, incluindo nas realizações de casos de uso os elementos de design necessários e as interações de elementos de design, conforme as regras de uso documentadas nas Diretrizes de Design.

Manipular Todas as Variantes do Fluxo de Eventos

Descreva cada variante de fluxo em um diagrama de seqüência separado. Diagramas de seqüência geralmente são preferíveis ao diagrama de comunicação, visto que sua leitura tende a ser mais fácil quando o diagrama precisa conter o nível de detalhe que normalmente se deseja obter ao projetar o sistema.

Comece descrevendo o fluxo básico, que é o mais comum ou o fluxo de eventos mais importante. Em seguida, descreva as variantes, como os fluxos excepcionais. Você não precisará descrever todos os fluxos de eventos, desde que empregue e exemplifique todas as operações dos objetos participantes. Desse modo, fluxos muito triviais poderão ser omitidos, como aqueles que só se concentram em um objeto.

Estude o caso de uso para verificar se há outras variantes de fluxo além das já descritas na captura e na análise de requisitos, por exemplo, aquelas que dependem de implementação. À medida que for identificando novos fluxos, descreva cada um deles em um diagrama de seqüência. Veja a seguir alguns exemplos de fluxos excepcionais.

  • Manipulação de erros. Se uma interface relatar que um erro ocorreu em sua comunicação com algum sistema externo, por exemplo, o caso de uso deverá lidar com isso. Uma possível solução é abrir uma nova rota de comunicação.
  • Manipulação de tempo limite. Se o usuário não responder dentro de um certo período, o caso de uso deverá tomar algumas medidas especiais.
  • Manipulação de entrada incorreta nos objetos que participam do caso de uso. Erros como este podem se originar de uma entrada incorreta do usuário.

Manipular Partes Opcionais do Casos de Uso

Você pode descrever um caminho alternativo de um fluxo como um fluxo opcional em vez de como uma variante. A lista a seguir inclui dois exemplos de fluxos opcionais.

  • Ao enviar um sinal, o agente decide, a partir de várias opções, a ação a ser executada em seguida pelo caso de uso. O caso de uso solicitou que o agente responda sim ou não a uma pergunta, por exemplo ou forneceu ao agente uma variedade de funções que o sistema pode executar no estado atual do caso de uso.
  • O caminho de fluxo varia dependendo do valor dos relacionamentos ou dos atributos armazenados. O fluxo de eventos subseqüente depende do tipo de dado a ser processado.

Se desejar que um fluxo opcional ou qualquer subfluxo complexo fique especialmente destacado, use um diagrama de seqüência separado. Cada diagrama de seqüência separado deve ser referido no diagrama de seqüência do fluxo principal de eventos através de scripts, texto ou anotações nas margens para indicar onde o comportamento do subfluxo ou o comportamento opcional ocorre.

Quando o comportamento de fluxo opcional ou excepcional puder ocorrer em qualquer parte, por exemplo, o comportamento executado quando um determinado evento ocorre, o diagrama de seqüência do fluxo principal de eventos deverá ser anotado para indicar que quando o evento ocorrer, o comportamento descrito no diagrama de seqüência opcional/excepcional será executado. Você também pode, no caso de um comportamento significativo controlado por eventos, utilizar diagramas de estados para descrever o comportamento do sistema. obter informações adicionais, consulte Diretriz: Diagrama de Estados.

Simplificar Diagramas de Seqüência Utilizando Subsistemas (Opcional)

Quando um caso de uso é realizado, o fluxo de eventos é geralmente descrito em termos dos objetos de execução , ou seja, como uma interação entre os objetos de design. Para simplificar os diagramas para identificar o comportamento reutilizável, talvez seja necessário encapsular um subfluxo de eventos dentro de um subsistema. Nesse caso, grandes subseções do diagrama de seqüência serão substituídas por uma única mensagem para o subsistema. No sistema, um diagrama de seqüências separado pode ilustrar as interações internas do subsistema que fornecem o comportamento exigido (para obter informações adicionais, consulte Tarefa: Design de Subsistema).

As subseqüências de mensagens dentro dos diagramas de seqüência deverão ser encapsuladas dentro de uma subsistema quando:

  • A subseqüência ocorrer repetidamente em diferentes realizações de casos de uso; isto é, as mesmas mensagens (ou semelhantes) são enviadas para os mesmos objetos (ou semelhantes), fornecendo o mesmo resultado final. A frase 'semelhante' é utilizada porque um trabalho de design poderá precisar tornar o comportamento reutilizável.
  • A subseqüência ocorre em apenas uma realização de casos de uso, mas espera-se que seja executada repetidamente em futuras iterações ou em sistemas semelhantes no futuro. O comportamento poderá criar um componente reutilizável adequado.
  • A subseqüência ocorre em apenas uma realização de casos de uso, é complexa apesar de ser facilmente encapsulada, precisa ter a responsabilidade de uma pessoa ou equipe e fornece um resultado bem definido. Nesses tipos de situações, o comportamento complexo geralmente exige um conhecimento técnico ou um conhecimento de domínio especial, e, conseqüentemente, é bem adequado para ser encapsulado dentro de um subsistema.
  • A subseqüência é determinada para ser encapsulada em um componente substituível (consulte Conceito: Componente). Nesse caso, um subsistema é a representação apropriada para o componente dentro do modelo de design.

Diagrama descrito no texto associado.

Uma realização de casos de uso pode ser descrita, se necessário, em vários níveis na hierarquia do subsistema. As linhas de vida no diagrama do meio representam subsistemas; as interações nos círculos representam a interação interna dos membros do subsistema em resposta à mensagem.

Vantagens dessa abordagem:

  • As realizações de casos de uso tornam-se menos desordenadas, especialmente se o design interno de alguns subsistemas for complexo.
  • As realizações de casos de uso podem ser criadas antes que os designs internos do subsistema sejam criados; isso é útil, por exemplo, em ambientes de desenvolvimento paralelos (consulte "Como Trabalhar em Paralelo").
  • As realizações de casos de uso tornam-se mais genéricas e fáceis de serem alteradas, especialmente se um subsistema precisar ser substituído por outro.

Exemplo:

Considere o seguinte diagrama de seqüência, que faz parte de uma realização do caso de uso Chamada Local:

Diagrama descrito no texto associado.

Nesse diagrama, as classes exibidas em cinza pertencem ao subsistema Administração de Rede; as outras classes pertencem ao subsistema Administração de Assinantes. Isso implica em um diagrama de seqüência de vários subsistemas , ou seja, em um diagrama no qual todos os objetos que participam do fluxo de eventos foram incluídos, independentemente de suas classes estarem ou não em diferentes subsistemas.

Como alternativa, podemos mostrar a chamada de comportamento no subsistema Administração de Rede e o exercício de uma interface específica nesse subsistema. Vamos considerar que o subsistema Administração de Rede forneça uma interface ICoordinator, usada pelo subsistema Administração de Assinantes:

Diagrama descrito no texto associado.

Essa interface é realizada pela classe Coordenador dentro de Administração de Rede. Nesse caso, podemos usar o próprio subsistema Administração de Rede e sua interface ICoordinator no diagrama de seqüência, em vez das instâncias de classes dentro de Administração de Rede:

Diagrama descrito no texto associado.

Observe que as instâncias de classe Coordenador, Informações sobre Dígitos e Rede são substituídas pelo subsistema que as contêm. Todas as chamadas para o subsistema são feitas através da interface ICoordinator.

Exibição de Interfaces nas Linhas de Vida

Para haver uma capacidade de substituição dos subsistemas que realizam a mesma interface, apenas as interfaces desses subsistemas devem estar visíveis nas interações (e nos diagramas em geral); caso contrário, as interações (ou os diagramas) precisarão ser alteradas quando um subsistema for substituído pelo outro.

Exemplo:

Podemos incluir apenas a interface ICoordinator, mas não seu subsistema provedor, em um diagrama de seqüência:

Diagrama descrito no texto associado.

Enviar uma mensagem para uma linha de vida de interface significa que qualquer subsistema que realize a interface poderá ser substituído pela interface do diagrama. Observe que a linha de vida da interface ICoordinator não possui mensagens de saída, visto que diferentes subsistemas que realizam a interface poderão enviar mensagens diferentes. No entanto, se você desejar descrever os tipos de mensagens a serem enviadas (ou com permissão para serem enviadas) de qualquer subsistema que esteja realizando a interface, essas mensagens poderão partir da linha de vida da interface.

Como Trabalhar em Paralelo

Em alguns casos, pode ser apropriado desenvolver um subsistema de forma mais ou menos independente e em paralelo com o desenvolvimento de outros subsistemas. Para isso, é necessário primeiro encontrar dependências de subsistema, identificando as interfaces entre eles.

O trabalho pode ser realizado da seguinte maneira:

  1. Concentre-se nos requisitos que afetam as interfaces entre os subsistemas.
  2. Faça esquemas das interfaces necessárias, mostrando as mensagens que passarão pelas bordas do subsistema.
  3. Desenhe diagramas de seqüência em termos dos subsistemas para cada caso de uso.
  4. Refine as interfaces necessárias para fornecer mensagens.
  5. Desenvolva cada subsistema em paralelo e use as interfaces como instrumentos de sincronização entre as equipes de desenvolvimento.

Você também pode escolher se deseja ordenar os diagramas de seqüência em termos dos subsistemas ou em termos apenas de suas interfaces. Em alguns projetos, pode até ser necessário implementar as classes, fornecendo as interfaces antes de você continuar com o resto da modelagem.

Descrever Comportamento Relacionado a Persistência

Toda a meta do paradigma orientado a objetos é encapsular os detalhes de implementação. Por isso, com relação à persistência, é preferível ter um objeto persistente que se pareça exatamente um objeto transiente. Não precisamos estar cientes de que o objeto é persistente ou tratá-lo de forma diferente do que trataríamos qualquer outro objeto. Essa pelo menos é a meta.

Na prática, talvez haja ocasiões em que o aplicativo precise controlar vários aspectos da persistência:

  • quando objetos persistentes forem lidos e gravados
  • quando objetos persistentes forem excluídos
  • como as transações são administradas
  • como o controle de bloqueio e simultaneidade é atingido

Gravando Objetos Persistentes

Existem dois casos a serem considerados: o tempo inicial no qual o objeto é gravado no armazenamento de objetos persistentes e as horas subseqüentes em que o aplicativo deseja atualizar o armazenamento de objetos persistentes com uma alteração no objeto.

Em qualquer um desses dois casos, o mecanismo específico depende das operações suportadas pelo framework de persistência. Em geral, o mecanismo usado consiste no envio de uma mensagem para o framework de persistência para criar o objeto persistente. Uma vez que um objeto seja persistente, o framework de persistência é inteligente o suficiente para detectar mudanças subseqüentes no objeto persistente e gravá-las no armazenamento de objetos persistentes quando necessário (em geral, quando uma transação for comprometida).

Um exemplo de objeto persistente sendo criado é mostrado abaixo:

Diagrama descrito no texto associado.

O objeto PersistenceMgr é uma instância de VBOS, um framework de persistência. O OrderCoordinator cria um Pedido persistente, enviando-o como argumento de uma mensagem 'createPersistentObject' para o PersistenceMgr.

Em geral, não é necessário modelar explicitamente isso, a menos que seja importante saber que o objeto está sendo armazenado explicitamente em um momento específico de uma seqüência de eventos. Se as operações subseqüentes precisarem consultar o objeto, ele deverá existir no banco de dados e, portanto, será importante saber que o objeto existirá lá.

Lendo Objetos Persistentes

A recuperação de objetos do armazenamento de objetos persistentes é necessária antes que o aplicativo envie mensagens para esse objeto. Lembre-se de que o trabalho em um sistema orientado a objetos é executado através do envio de mensagens para objetos. Mas se o objeto para o qual você deseja enviar uma mensagem estiver no banco de dados mas não na memória ainda, haverá um problema: você não conseguirá enviar uma mensagem para algo que ainda não existe!

Em resumo, você precisa enviar uma mensagem para um objeto que saiba como consultar o banco de dados, recuperar o objeto correto e instanciá-lo. Somente depois disso você poderá enviar a mensagem original que pretendia enviar. O objeto que instancia um objeto persistente às vezes é chamado de depósito de informações. Um objeto depósito de informações é responsável por criar instâncias de objetos, incluindo objetos persistentes. Com base em uma consulta, o depósito de informações poderia ser designado para retornar um conjunto de um ou mais objetos que correspondessem à consulta.

Em geral, os objetos estão tão bem conectados uns aos outros através de suas associações que é comum ser necessário recuperar apenas o objeto raiz em um gráfico de objetos; o restante é "extraído" do banco de dados de forma essencialmente transparente, de acordo com suas respectivas associações com o objeto raiz. (Um mecanismo de persistência adequado é sensível a isso: ele só recupera objetos quando eles são necessários; caso contrário, acabaríamos tentando instanciar um grande número de objetos sem necessidade. A recuperação de objetos antes que sejam necessários é um dos principais problemas de desempenho causados por mecanismos de persistência simplistas.)

O exemplo a seguir mostra como a recuperação de um objeto do armazenamento de objetos persistentes pode ser modelada. Em um diagrama de seqüências real, o DBMS não seria mostrado, visto que deveria ser encapsulado no objeto depósito de informações.

Diagrama descrito no texto associado.

Excluindo Objetos Persistentes

O problema com objetos persistentes é que eles persistem! Ao contrário dos objetos transientes que simplesmente desaparecem quando o processo que os criou é eliminado, os objetos persistentes existem até serem excluídos explicitamente. Por isso, é importante excluir o objeto quando ele não estiver mais sendo utilizado.

O problema é que isso é difícil de ser determinado. Só porque um aplicativo terminou de usar o objeto não significa que todos os aplicativos, atuais e futuros, também terminaram de usá-lo. E como os objetos não só podem como de fato possuem associações sobre as quais nem mesmo sabem, nem sempre é fácil descobrir se é correto excluir um objeto.

Em design, isso pode ser representado semanticamente, utilizando gráficos de estado: quando o objeto atinge o estado final, pode-se dizer que ele está liberado. Os desenvolvedores responsáveis pela implementação das classes persistentes poderão usar, então, as informações do diagrama de estados para disparar o comportamento apropriado do mecanismo de persistência a fim de liberar o objeto. A responsabilidade do Designer da realização de casos de uso é chamar as operações apropriadas para fazer com que o objeto atinja seu estado final quando é adequado excluí-lo.

Se um objeto estiver muito bem conectado a outros objetos, poderá ser difícil determinar se ele pode ser excluído. Visto que um objeto depósito de informações conhece a estrutura do objeto e também dos demais aos quais ele está conectado, muitas vezes é útil carregar o objeto depósito de informações com uma classe cuja responsabilidade seja determinar se uma instância específica pode ser excluída. A estrutura de persistência também pode fornecer suporte para esse recurso.

Modelando Transações

As transações definem um conjunto de chamadas de operação que são indivisíveis, isto é ou são todas executadas ou nenhuma delas é executada. No contexto da persistência, uma transação define um conjunto de mudanças para um conjunto de objetos que são todas executadas ou nenhuma é executada. As transações oferecem consistência, assegurando que conjuntos de objetos passem de um estado consistente para outro.

Há várias opções que mostram transações em Realizações de Casos de Uso:

  • Textualmente. Usando scripts na margem do diagrama de seqüência, é possível documentar as fronteiras de transação conforme mostrado abaixo. Este método é simples e permite o uso de qualquer número de mecanismos para implementar a transação.

Diagrama descrito no texto associado.

Representação das fronteiras de transação usando anotações textuais.

  • Utilizando Mensagens Explícitas. Se o mecanismo de gerenciamento de transação usado empregar mensagens explícitas para iniciar e encerrar transações, essas mensagens poderão ser mostradas explicitamente no diagrama de seqüência, conforme mostrado abaixo:

Diagrama descrito no texto associado.

Diagrama de seqüência mostrando mensagens explícitas para iniciar e encerrar transações.

Manipulando Condições de Erro

Se não for possível executar todas as operações de uma transação (geralmente, por causa de um erro ocorrido), a transação será interrompida e todas as mudanças feitas durante a transação serão revertidas. Condições de erro antecipadas muitas vezes representam fluxos de eventos excepcionais em casos de uso. Em outros casos, as condições de erro ocorrem devido a alguma falha no sistema. As condições de erro também devem ser documentadas em interações. Exceções e erros simples podem ser mostrados na interação onde ocorreram; exceções e erros complexos podem exigir suas próprias interações.

Os modos de falha de objetos específicos podem ser mostrados em diagramas de estados. O fluxo condicional do tratamento de controle desses modos de falha pode ser mostrado na interação em que o erro ou a exceção ocorreu.

Manipulando Controle de Simultaneidade

A simultaneidade descreve o controle de acesso a recursos críticos do sistema durante uma transação. Para manter o sistema em um estado consistente, uma transação pode exigir que ele tenha acesso exclusivo a determinados recursos-chave do sistema. A exclusividade pode incluir a capacidade de leitura de um conjunto de objetos, a gravação de um conjunto de objetos ou a leitura e a gravação de um conjunto de objetos.

Vamos examinar um exemplo simples do motivo pelo qual poderemos precisar restringir o acesso a um conjunto de objetos. Digamos que esteja em execução um sistema simples de entrada de pedidos. As pessoas ligam para fazer pedidos e nós processamos e enviamos os pedidos. Podemos considerar o pedido como um tipo de transação.

Para ilustrar a necessidade de controle de simultaneidade, vamos supor que eu ligue solicitando um novo par de botas para caminhada. Quando a entrada do pedido é feita no sistema, ele verifica se as botas que desejo, no tamanho correto, existem no estoque. Se existirem, é feita a reserva desse par para que ninguém mais possa comprá-las antes do envio do pedido. Quando o pedido é enviado, as botas são retiradas do estoque.

Durante o período entre o pedido ser feito e enviado, as botas ficam em um estado especial—elas estão no estoque, mas estão "comprometidas" com meu pedido. Se o meu pedido for cancelado por algum motivo (se eu mudar de idéia ou o meu cartão de crédito tiver expirado), as botas voltarão para o estoque. Quando o pedido for enviado, vamos considerar que nossa pequena empresa não deseje manter um registro dessas botas.

A meta da simultaneidade, como nas transações, é assegurar que o sistema passe de um estado consistente para outro. Além disso, a simultaneidade procura assegurar que uma transação tenha todos os recursos de que precisa para concluir seu trabalho. O controle da simultaneidade pode ser implementado de várias maneiras diferentes, incluindo bloqueio de recursos, semáforos, travas de memória compartilhadas e espaços de trabalho privados.

Em um sistema orientado a objetos, é difícil saber apenas pelos padrões de mensagem se uma mensagem específica pode causar uma mudança de estado em um objeto. Além disso, diferentes implementações podem prevenir para a necessidade de restringir o acesso a determinados tipos de recursos; por exemplo, algumas implementações fornecem a cada transação sua própria visão do estado do sistema no início da transação. Nesse caso, outros processos podem alterar o estado de um objeto sem afetar a 'visualização' de qualquer outra transação em execução.

Para evitar restrição da implementação, no design desejamos simplesmente indicar os recursos aos quais a transação deve ter acesso exclusivo. Usando o exemplo anterior, desejamos indicar que precisamos de acesso exclusivo às botas que foram pedidas. Uma alternativa simples é anotar a descrição da mensagem que está sendo enviada, indicando que o aplicativo precisa de acesso exclusivo ao objeto. O Implementador poderá, então, usar essa informação para determinar a melhor maneira de implementar o requisito de simultaneidade. Um exemplo de diagrama de seqüência mostrando a anotação das mensagens que exigem acesso exclusivo é mostrado abaixo. A suposição é que todos os bloqueios sejam liberados quando a transação for concluída.

Diagrama descrito no texto associado.

Exemplo mostrando o controle de acesso anotado em um diagrama de seqüência.

O motivo para a não restrição do acesso a todos os objetos necessários em uma transação é que muitas vezes apenas alguns objetos devem ter restrições de acesso; restringir o acesso a todos os objetos que participam de uma transação desperdiça recursos valiosos e poderia criar, em vez de evitar, gargalos de desempenho.

Refinar a Descrição do Fluxo de Eventos

No fluxo de eventos da realização de casos de uso, você talvez precise acrescentar uma descrição aos diagramas de seqüência, nos casos em que o fluxo de eventos não fica totalmente claro apenas com o exame das mensagens enviadas entre os objetos participantes. Alguns exemplos incluem casos onde são necessárias anotações de tempo, observações sobre comportamento condicional ou algum esclarecimento sobre o comportamento da operação para facilitar a leitura dos diagramas por observadores externos.

O fluxo de eventos é delineado inicialmente na Tarefa: Análise de Caso de Uso. Nesse passo, você refina o fluxo de eventos conforme necessário para esclarecer os diagramas de seqüência.

Muitas vezes, o nome da operação não é suficiente para entender por que a operação está sendo executada. Anotações de texto ou scripts na margem do diagrama podem ser necessários para esclarecer o diagrama de seqüência. Eles também podem ser necessários para representar o fluxo de controle, como passos de decisão, looping e ramificação. Além disso, marcas de texto talvez sejam necessárias para correlacionar os pontos de extensão no caso de uso com locais específicos nos diagramas de seqüência.

Exemplos anteriores dentro dessa tarefa já ilustraram várias maneiras diferentes de anotar diagramas de seqüência.



Unificar Classes e Subsistemas de Design

Conforme os casos de uso são realizados, é necessário unificar as classes e subsistemas de design identificados para assegurar a homogeneidade e consistência do Modelo de Design.

Pontos a serem considerados:

  • Os nomes dos elementos do modelo devem descrever sua função.
  • Evite nomes semelhantes e sinônimos porque eles dificultam a distinção dos elementos do modelo.
  • Mescle elementos do modelo que definam um comportamento semelhante ou que representem o mesmo fenômeno.
  • Mescle classes de entidades que representam o mesmo conceito ou que possuem os mesmos atributos, mesmo que seu comportamento definido seja diferente.
  • Use a herança para abstrair elementos do modelo, o que tende a tornar o modelo mais robusto.
  • Ao atualizar um elemento do modelo, atualize também a descrição do fluxo de eventos correspondente das realizações de casos de uso.
Avaliar Seus Resultados

Verifique o modelo de design neste estágio para se certificar de que seu trabalho esteja na direção certa. Não há necessidade de revisar o modelo de design detalhadamente mas, enquanto trabalha nele, leve em consideração o Modelo de Design Model.

Consulte especialmente Realização de Caso de Uso, na Tarefa: Revisar o Design.

Informações Adicionais