Utilizar Padrões e Mecanismos de Design
Utilize padrões e mecanismos de design conforme adequado à classe ou ao recurso que está sendo projetado e de acordo
com as diretrizes de design do projeto.
A incorporação de um padrão e/ou mecanismo é executar com eficiência muitas das etapas subseqüentes desta tarefa
(incluindo novas classes, operações, atributos e relações), mas de acordo com as regras definidas pelo padrão ou
mecanismo.
Observe que padrões e mecanismos normalmente são incorporados conforme a evolução do design e não apenas como a
primeira etapa desta tarefa. Além disso, eles são freqüentemente aplicados a um conjunto de classes, e não apenas a uma
única classe.
|
Criar Classes de Design Inicial
Crie uma ou várias classes de design inicial para a classe de análise determinada como entrada para esta tarefa e
designe dependências de rastreio. As classes de design criadas nesta etapa serão refinadas, ajustadas, divididas ou
mescladas nas etapas subseqüentes, quando forem designadas várias propriedades de design - como operações, métodos e
uma máquina de estado - que descrevem como a classe de análise é projetada.
Dependendo do tipo da classe de análise (limite, entidade ou controle) que está sendo projetada, há estratégias
específicas que podem ser utilizadas para criar classes de design inicial.
Classes de limite representam interfaces para usuários ou para outros sistemas.
Normalmente, classes de limite que representam interfaces para outros sistemas são modeladas como subsistemas, porque
muitas vezes possuem comportamento interno complexo. Se o comportamento da interface for simples (talvez agindo apenas
como uma passagem para uma API existente para o sistema externo), será possível optar por representar a interface com
uma ou mais classes de design. Se essa for a sua escolha, utilize uma única classe de design por protocolo, interface
ou API e observe os requisitos especiais sobre padrões utilizados nos requisitos especiais da classe.
Classes de limite que representam interfaces para usuários geralmente seguem a regra de uma classe de limite para cada
janela ou uma para cada formulário, na interface com o usuário. Conseqüentemente, as responsabilidades das classes de
limite podem estar em um nível razoavelmente alto, sendo necessário serem refinadas e detalhadas nesta etapa. Modelos
adicionais ou protótipos da interface com o usuário podem ser outra origem de entrada a ser considerada nesta etapa.
O design das classes de limite depende das ferramentas de desenvolvimento da UI (interface com o usuário) disponíveis
para o projeto. Com o uso da tecnologia atual, é comum que a UI seja construída de forma visível diretamente na
ferramenta de desenvolvimento. Isso cria automaticamente as classes da UI que precisam ser relacionadas ao design das
classes de controle e de entidade. Se o ambiente de desenvolvimento da UI criar automaticamente as classes de suporte
necessárias para implementar a UI, não haverá necessidade de considerá-las no design. Você só projeta aquilo que o
ambiente de desenvolvimento não cria para você.
Durante a análise, as classes de entidade representam unidades manipuladas de informações. Muitas vezes, são passivas e
persistentes e podem ser identificadas e associadas ao mecanismo de análise para persistência. Os detalhes do design de
um mecanismo de persistência baseado em banco de dados são abordados em Tarefa: Design de
Banco de Dados. Considerações de desempenho podem forçar alguma recriação das classes persistentes, provocando
alterações no Modelo de Design que são discutidas em conjunto entre a Função:
Designer de Banco de Dados e a Função: Designer.
Uma discussão mais ampla dos problemas de design das classes persistentes será apresentada mais tarde sob o título Identificar Classes Persistentes.
Um objeto de controle é responsável pelo gerenciamento do fluxo de um caso de uso e, portanto, coordena a maioria de
suas ações; objetos de controle encapsulam a lógica que não está particularmente relacionada às questões da interface
com o usuário (objetos de limite) ou da engenharia de dados (objetos de entidade). Essa lógica às vezes é chamada de
lógica do aplicativo ou lógica de negócios.
Leve em consideração as seguintes questões quando classes de controle forem projetadas:
-
Complexidade - Você pode manipular comportamentos descomplicados, de coordenação ou de controle, utilizando
classes de limite ou de entidade. Entretanto, conforme aumenta a complexidade do aplicativo, podem surgir
obstáculos significativos para essa abordagem, tais como:
-
o comportamento de coordenação de casos de uso incorpora-se na UI, tornando mais difícil alterar o sistema
-
a mesma UI não pode ser utilizada em diferentes realizações de casos de uso sem dificuldades
-
a UI fica sobrecarregada com funcionalidade adicional, reduzindo seu desempenho
-
os objetos de entidade ficam sobrecarregados com o comportamento específico do caso de uso, reduzindo sua
generalidade
Para evitar esses problemas, as classes de controle foram introduzidas para fornecer o comportamento relacionado à
coordenação dos fluxos de eventos.
-
Probabilidade de alteração - Se houver pouca probabilidade de alterar os fluxos de eventos ou o custo for
insignificante, a despesa extra e a complexidade de classes de controle adicionais podem não ser justificáveis.
-
Distribuição e desempenho - A necessidade de executar partes do aplicativo em nós diferentes ou em espaços
de processo diferentes, leva à necessidade de especializar os elementos de modelo de design. Freqüentemente, essa
especialização é acompanhada da inclusão de objetos de controle e da distribuição de comportamento das classes de
fronteira e das classes de entidade para as classes de controle. Fazendo isso, as classes de limite passam a
fornecer apenas serviços da UI, as classes de entidade passam a fornecer apenas serviços de dados e as classes de
controle fornecem o restante.
-
Gerenciamento de transações - Gerenciar transações é uma atividade de coordenação clássica. Sem um estrutura
para tratar o gerenciamento de transações, uma ou mais classes de gerenciador de transações teria de
interagir para assegurar a manutenção da integridade das transações.
Nos dois últimos casos, se a classe de controle representar um encadeamento de controle separado, será mais apropriado
utilizar uma classe ativa para modelar o encadeamento de controle. Em um sistema de tempo real, o uso do Produto de Trabalho: Cápsulas é a abordagem de modelagem
preferencial.
|
Identificar Classes Persistentes
As classes que precisam armazenar seu estado em uma mídia permanente são denominadas persistentes. A necessidade de
armazenar seu estado pode ser para registrar permanentemente as informações de classe, para fins de backup em caso de
falha do sistema ou para troca de informações. Uma classe persistente pode ter instâncias persistentes ou provisórias;
rotular uma classe como persistente significa apenas que algumas instâncias da classe talvez precisem ser persistentes.
Incorpore os mecanismos de design que correspondem aos mecanismos de persistência encontrados durante a análise. Por
exemplo, dependendo do que for exigido pela classe, o mecanismo de análise no que diz respeito a persistência pode ser
executado por um dos seguintes mecanismos de design:
-
Armazenamento em memória
-
Placa Flash
-
Arquivo binário
-
Sistema de Gerenciamento de Banco de Dados (DBMS)
Os objetos persistentes podem não ser derivados das classes de entidade somente; eles podem também ser necessários para
tratar requisitos não-funcionais em geral. Os exemplos seriam os objetos persistentes necessários para manter
informações relevantes ao controle de processos ou para manter informações de estado entre as transações.
A identificação de classes persistentes é apropriada para notificar a Função:
Designer de Banco de Dados de que a classe exige atenção especial às suas características de armazenamento físico.
Ela também notifica a Função: Arquiteto de Software de que a classe precisa ser persistente
e a Função: Designerresponsável pelo mecanismo de persistência de que as
instâncias da classe precisam se tornar persistentes.
Devido à necessidade de uma estratégia de persistência coordenada, a Função:
Designer de Banco de Dados é responsável pelo mapeamento das classes persistentes no banco de dados, utilizando uma
estrutura de persistência. Se o projeto estiver desenvolvendo um framework de persistência, o desenvolvedor do
framework também será responsável por conhecer os requisitos de persistência das classes de design. Para fornecer a
essas pessoas as informações que elas precisam, é suficiente nesse ponto indicar que a classe é persistente ou, mais
precisamente, que as instâncias da classe são persistentes.
|
Definir Visibilidade da Classe
Para cada classe, determine a visibilidade que ela terá no pacote em que reside. Uma classe pública pode ser
referenciada fora do pacote que a contém. Uma classe privada (ou uma cuja visibilidade é implementação)
só poderá ser referenciada pelas classes que estão dentro do mesmo pacote.
|
Definir Operações
Para identificar operações em classes de design:
-
Estude as responsabilidades de cada classe de análise correspondente criando uma operação para cada
responsabilidade. Use a descrição da responsabilidade como a descrição inicial da operação.
-
Estude as realizações de casos de uso nas participações de classe para ver como as operações são utilizadas
pelas realizações de casos de uso. Amplie as operações, uma realização de caso de uso por vez, refinando as
operações, suas descrições, tipos de retorno e parâmetros. Os requisitos de cada realização de caso de uso
pertencentes às classes são descritos textualmente no Fluxo de Eventos da realização de caso de uso.
-
Analise o caso de uso Requisitos Especiais para certificar-se de não faltar nenhum requisito implícito na operação
que poderá ser declarada.
As operações devem oferecer suporte às mensagens em diagramas de seqüência porque os scripts - especificações de
mensagem temporária que ainda não foram designadas para as operações - descrevem o comportamento esperado da classe. A
figura 1 ilustra o exemplo de um diagrama de seqüência.
Figura 1: Mensagens Formam a Base para Identificar Operações
As realizações de casos de uso fornecem informações suficientes para identificar todas as operações. Para encontrar as
outras operações, considere o seguinte:
-
Há alguma maneira de inicializar uma nova instância da classe, inclusive por meio da conexão com instâncias de
outras classes às quais ela esteja associada?
-
Há necessidade de teste para saber se duas instâncias da classe são iguais?
-
Há necessidade de criar uma cópia de uma instância da classe?
-
Há necessidade de os mecanismos usados pela classe executarem alguma operação? Por exemplo, um mecanismo de
coleta de lixo poderia exigir que um objeto elimine todas as referências aos demais objetos para que os
recursos não utilizados possam ser liberados.
Não defina operações que apenas obtêm e definem os valores de atributos públicos (consulte Definir Atributos e Definir Associações).
Normalmente, essas operações são geradas pelos recursos de geração de código e não precisam ser definidas
explicitamente.
Utilize as convenções de nomenclatura da linguagem de implementação quando estiver nomeando operações, tipos de
retorno, bem como parâmetros e seus tipos. Estes são descritos nas Diretrizes Específicas do Projeto.
Para cada operação, você deve definir:
-
O nome da operação - mantenha-o curto e descritivo do resultado que a operação alcança.
-
Os nomes de operação devem seguir a sintaxe da linguagem de implementação. Exemplo: find_location
seria aceitável para C++ ou Visual Basic, mas não para Smalltalk (que não utiliza caractere de sublinhado);
um nome mais adequado para todas as linguagens seria findLocation.
-
Evite nomes que sugira como a operação é executada. Por exemplo, Employee.wages() é melhor que
Employee.calculateWages(), visto que o último sugere a execução de um cálculo. A operação poderá
simplesmente retornar um valor em um banco de dados.
-
O nome da operação deve demonstrar claramente sua finalidade. Evite nomes não específicos, como
getData, que não descrevem o resultado que retornam. Use um nome que mostre exatamente o que se
espera, como getAddress. Melhor ainda, basta que o nome da operação seja o nome da propriedade que
será retornada ou definida. Se ela tiver um parâmetro, ela definirá a propriedade. Se ela não tiver nenhum
parâmetro, ela obterá a propriedade. Exemplo: a operação address retorna o endereço de um
Cliente, enquanto address(aString) define ou altera o endereço do Cliente. A natureza
get e set da operação é implícita à assinatura da operação.
-
As operações conceitualmente idênticas devem ter o mesmo nome, ainda que sejam definidas por classes
distintas, implementadas de maneiras totalmente diferentes ou não tenham número igual de parâmetros. Uma
operação que cria um objeto, por exemplo, deve ter o mesmo nome em todas as classes.
-
Se as operações em várias classes tiverem a mesma assinatura, a operação deverá retornar o mesmo tipo de
resultado, apropriado ao objeto receptor. Esse é um exemplo do conceito de polimorfismo, o qual
afirma que objetos diferentes devem responder à mesma mensagem de maneira semelhante. Exemplo: a operação
name deve retornar o nome do objeto, não importando como o nome é armazenado ou derivado. Siga esse
princípio para facilitar a compreensão do modelo.
-
O tipo de retorno - O tipo de retorno deve ser a classe do objeto retornado pela operação.
-
Uma descrição curta - Tão expressivo quanto possível, o nome da operação muitas vezes é vago e, portanto,
não muito útil para tentar entender o que a operação executa. Forneça à operação uma descrição curta que consista
em algumas sentenças, escritas segundo a perspectiva do usuário da operação.
-
Os parâmetros - Para cada parâmetro, crie um nome descritivo curto, decida sua classe e forneça uma
descrição resumida. Quando especificar parâmetros, lembre-se de que quanto menos parâmetros, maior é a usabilidade.
Um número pequeno de parâmetros torna a operação mais fácil se ser entendida, havendo maior probabilidade de
encontrar operações semelhantes. Talvez seja necessário dividir uma operação com vários parâmetros em várias
operações. A operação deve ser compreendida por aqueles que desejam utilizá-la. A descrição curta deve incluir:
-
o significado dos parâmetros, caso seus nomes não o evidencie
-
se o parâmetro é transmitido por valor ou por referência
-
parâmetros que devem ter valores fornecidos
-
parâmetros que podem ser opcionais e seus valores padrão, se nenhum valor for fornecido
-
intervalos válidos para parâmetros, se aplicável
-
o que é feito na operação
-
quais parâmetros por referência são alterados pela operação
Uma vez definidas as operações, preencha nos diagramas de seqüência as informações sobre quais operações são chamadas
para cada mensagem.
Consulte a seção intitulada Diretriz do Produto de Trabalho: Classe de Design, para obter informações adicionais.
Para cada operação, identifique a visibilidade de exportação da operação dentre estas opções:
-
Pública - a operação é visível para modelar elementos que não sejam a própria classe.
-
Implementação - a operação é visível somente dentro da própria classe.
-
Protegida - a operação é visível somente para a própria classe, para suas subclasses ou para amigos
da classe (dependente de linguagem).
-
Privada - a operação é visível somente para a própria classe e para amigos da classe
Escolha a visibilidade que, embora seja a mais restrita, ainda possa atender aos objetivos da operação. Para fazer
isso, examine os diagramas de seqüência e, para cada mensagem, determine se ela provém de uma classe fora do pacote do
receptor (requer visibilidade pública), de dentro do pacote (requer visibilidade de implementação), de
uma subclasse (requer visibilidade protegida) ou da própria classe ou de um amigo (requer visibilidade
privada).
Em geral, operações são operações de instância , ou seja, são executadas em instâncias da classe. Em alguns casos, no
entanto, uma operação se aplica a todas as instâncias da classe; por isso, é uma operação de escopo de classe. O
receptor da operação de classe é de fato uma instância de uma metaclasse - a descrição da própria classe - e não
qualquer instância específica da classe. Exemplos de operações de classe incluem mensagens que criam (instanciam) novas
instâncias que retornam todas as Instâncias de uma classe.
A cadeia da operação é sublinhada para indicar uma operação de escopo de classe.
|
Definir Métodos
Um método especifica a implementação de uma operação. Em muitos casos nos quais o comportamento exigido pela operação é
suficientemente definido pelo nome, pela descrição e pelos parâmetros da operação, os métodos são implementados
diretamente na linguagem de programação. Quando a implementação de uma operação exige o uso de um algoritmo específico
ou mais informações do que as apresentadas na descrição da operação, uma descrição de método separada é
necessária. O método descreve como a operação funciona, não apenas o que ela faz.
O método deve discutir como fazer o seguinte:
-
as operações serão implementadas
-
os atributos serão implementados e utilizados para implementar operações
-
as relações serão implementadas e utilizadas para implementar operações
Os requisitos irão variar conforme o caso; contudo, as especificações de método para uma classe deverão declarar
sempre:
-
o que será feito de acordo com os requisitos
-
quais os outros objetos e suas descrições serão utilizados
Requisitos mais específicos poderão incluir:
-
como os parâmetros serão implementados
-
quais, se houver, algoritmos especiais serão utilizados
Os diagramas de seqüência são uma importante fonte para esse tipo de informação. A partir daí, ficará claro quais
operações serão utilizadas em outros objetos quando uma operação for executada. Para a implementação completa de uma
operação, é necessária uma especificação de quais operações serão utilizadas em outros objetos. A produção de uma
especificação completa de método, portanto, exige identificar as operações para os objetos envolvidos e inspecionar os
diagramas de seqüência correspondentes.
|
Definir Estados
Em algumas operações, o comportamento da operação depende do estado no qual se encontra o objeto receptor. Uma máquina
de estado é uma ferramenta que descreve os estados que um objeto pode assumir e os eventos que fazem com que ele se
mova de um estado para outro (consulte Técnica:
Diagrama de Estados). As máquinas de estado são bastante úteis para descrever as classes ativas. O uso de máquinas
de estado é particularmente importante para definir o comportamento do Produto e
Trabalho: Cápsulas.
Na figura 2, é mostrado o exemplo de uma máquina de estado simples.
Figura 2: Um Diagrama de Estado Simples de uma Bomba de Combustível
Cada evento de transição de estado pode ser associado a uma operação. Dependendo do estado do objeto, a operação poderá
ter um comportamento diferente e os eventos de transição descrevem como isso ocorre.
A descrição do método referente à operação associada deve ser atualizada com informações específicas do estado,
indicando a cada estado relevante o que a operação deve fazer. Os estados muitas vezes são representados utilizando
atributos; os diagramas de estado servem como entrada na etapa de identificação dos atributos.
Para obter informações adicionais, consulte Técnica:
Diagrama de Estados.
|
Definir Atributos
Durante a definição de métodos e a identificação de estados, são identificados os atributos que a classe
precisa para executar suas operações. Os atributos fornecem armazenamento de informações para a instância da classe e
muitas vezes são utilizados para representar o estado da instância da classe. Qualquer informação que a própria classe
mantém ela o faz através de seus atributos. Para cada atributo, defina:
-
seu nome, que deve obedecer às convenções de nomenclatura da linguagem de implementação e do projeto
-
seu tipo, que será um tipo de dado elementar suportado pela linguagem de implementação
-
seu valor padrão ou inicial, com o qual é inicializado quando novas instâncias da classe são criadas
-
a visibilidade, que irá adotar um dos seguintes valores:
-
Público: o atributo é visível dentro e fora da pacote que contém a classe
-
Protegido: o atributo é visível somente para a própria classe, para suas subclasses ou para amigos
da classe (dependente da linguagem)
-
Privado: o atributo é visível somente para a própria classe e para amigos da classe
-
Implementação: o atributo é visível somente para a própria classe
-
classes persistentes, se o atributo é persistente (o padrão) ou temporário. Embora a própria classe possa
ser persistente, nem todos os atributos da classe precisam ser persistentes
Verifique se todos os atributos são necessários. Os atributos devem ser justificados - é fácil incluir os atributos no
início do processo e mantê-los após não mais serem necessários, por falta de perspectiva. Atributos extras,
multiplicados por milhares ou milhões de instâncias, podem causar um efeito prejudicial sobre os requisitos de
desempenho e armazenamento de um sistema.
Consulte a seção intitulada Atributos em Diretriz de Produto de
Trabalho: Classe de Design, para obter informações adicionais sobre os atributos.
|
Definir Dependências
Para cada caso em que a comunicação entre os objetos é necessária, levante as seguintes questões:
-
A referência a um receptor é transmitida como um parâmetro para a operação? Se a resposta for sim, estabeleça uma
dependência entre as classes emissora e receptora de um diagrama que contenha as duas classes. Além disso,
se o formato do diagrama de comunicação para interações for utilizado, qualifique a visibilidade de link e
defina-a como parâmetro.
-
O receptor é global? Se a resposta for sim, estabeleça uma dependência entre as classes emissora e receptora
de um diagrama que contenha as duas classes. Além disso, se o formato do diagrama de comunicação para
interações for utilizado, qualifique a visibilidade de link e defina-a como global.
-
O receptor é um objeto temporário criado e destruído durante a própria operação? Se a resposta for sim, estabeleça
uma dependência entre as classes emissora e receptora de um diagrama que contenha as duas classes. Além
disso, se o formato do diagrama de comunicação para interações for utilizado, qualifique a visibilidade de
link e defina-a como local.
Observe que os links modelados dessa forma são temporários, existindo apenas por um período limitado no contexto
específico da colaboração - nesse sentido, eles são instâncias da função de associação na colaboração. Contudo, a
relação em um modelo de classe (isto é, independente de contexto) deve ser de dependência, conforme descrito
anteriormente. Conforme [RUM98] declara, na
definição de link temporário: "É possível modelar todos esses links como associações, mas as condições nas
associações devem ser declaradas de forma bem ampla e eles perdem muito de sua precisão quando limitam combinações de
objetos." Nesta situação, a modelagem de uma dependência é menos importante do que a modelagem do relacionamento na
colaboração, porque dependência não descreve o relacionamento completamente; somente que ele existe.
|
Definir Associações
As associações proporcionam o mecanismo para os objetos se comunicarem entre si. Elas fornecem aos objetos um canal
pelo qual as mensagens podem fluir. Além disso, documentam as dependências entre as classes, destacando que as mudanças
em uma classe podem ser percebidas entre muitas outras classes.
Examine as descrições de método para cada operação a fim de entender como as instâncias da classe se comunicam e
colaboram com outros objetos. Para enviar uma mensagem para outro objeto, um objeto deve ter uma referência para o
receptor da mensagem. Um diagrama de comunicação (representação alternativa de um diagrama de seqüência) mostrará a
comunicação do objeto em termos de links, conforme ilustrado na figura 3.
Figura 3: Exemplo de um Diagrama de Comunicação
As mensagens restantes utilizam associação ou agregação para especificar a relação entre instâncias de
duas classes que se comunicam. ConsulteTécnica: Associação
e Técnica: Agregação, para obter informações sobre a escolha da representação
apropriada. No caso dessas duas associações, defina a visibilidade de link como campo nos diagramas de
comunicação. Outros tarefas:
-
Estabelecer a navegabilidade das associações e agregações. Para fazer isso, considere que tipo de navegabilidade é
necessária nas respectivas instâncias de link, nos diagramas de interação. Visto que a navegabilidade, por padrão,
é verdadeira, você só precisa encontrar as associações (e agregações) nas quais todas as funções de links
opostos de todos os objetos de uma classe na associação não exigem navegabilidade. Nesses casos, defina a
navegabilidade como falsa na função da classe.
-
Se houver atributos na própria associação (representada por classes de associação), crie uma classe de design para
representar a classe de associação, com os atributos adequados. Intercale essa classe entre as outras duas classes
e estabeleça associações com a multiplicidade adequada entre a classe de associação e as outras duas classes.
-
Especifique se as extremidades da associação devem ou não ser ordenadas; é o ocorre quando os objetos
associados a um objeto na outra extremidade da associação tem uma ordenação que deve ser preservada.
-
Se a classe associada (ou agregada) for consultada apenas pela classe atual, considere a possibilidade de aninhar a
classe. As vantagens do aninhamento de classes incluem serviço de mensagens mais rápido e um modelo de design mais
simples. As desvantagens incluem espaço para a classe aninhada alocado estaticamente, mesmo que haja instâncias da
classe aninhada, falta de identidade do objeto separada da classe de inclusão ou incapacidade para consultar
instâncias de classes aninhadas fora da classe de inclusão.
Associações e agregações são melhor definidas em um diagrama que representa as classes associadas. O diagrama de
classes deve ser de propriedade do pacote que contém as classes associadas. A figura 4 ilustra um exemplo de
diagrama de classe, representando associações e agregações.
Figura 4: Exemplo de um Diagrama de Classe Mostrando Associações, Agregações e Generalizações entre as Classes
As associações de assinatura entre as classes de análise são utilizadas para identificar dependências de eventos
entre as classes. No Modelo de Design, é necessário tratar essas dependências de eventos explicitamente, seja
utilizando as estruturas de rotina de tratamento de eventos disponíveis, seja projetando e criando sua própria
estrutura de rotina de tratamento de eventos. Em algumas linguagens de programação, como Visual Basic, isso é feito
diretamente , ou seja, você declara, promove e trata os eventos correspondentes. Em outras linguagens, talvez seja
preciso utilizar uma biblioteca adicional de funções reutilizáveis para tratar assinaturas e eventos. Se não for
possível adquirir a funcionalidade, ela terá de ser projetada e criada. Consulte também Técnica: Associação de Assinatura.
|
Definir Estrutura Interna
Algumas classes podem representar abstrações complexas e ter uma estrutura complexa. Ao modelar uma classe, talvez o
designer prefira representar suas relações e elementos internos participantes, para ter certeza de que o implementador
irá implementar adequadamente as colaborações que ocorrem nessa classe.
Na UML 2.0, as classes são definidas como classes
estruturadas, com o recurso para ter portas e uma estrutura interna. Dessa forma, as classes podem ser decompostas
em coleções de partes conectadas que, por sua vez, podem ser posteriormente decompostas. Uma classe pode ser
encapsulada, forçando a passagem das comunicações pelo lado externo através de portas que obedecem a interfaces
declaradas.
Quando encontrar uma classe complexa, com estrutura complexa, crie um diagrama de estrutura composta para essa classe.
Modele as partes que executarão as funções referentes ao comportamento da classe. Estabeleça como as partes serão
'ligadas' com o uso de conectores. Utilize portas com interfaces declaradas, se deseja permitir que clientes diferentes
dessa classe acessem partes específicas do comportamento oferecido por essa classe. Utilize também portas que isolem
completamente de seu ambiente as partes internas dessa classe.
Para obter informações adicionais sobre este tópico e exemplos sobre o diagrama de estrutura composta, consulte Conceito: Classe Estruturada.
|
Definir Generalizações
As classes poderão ser organizadas em uma hierarquia de generalização para refletir um comportamento e uma estrutura
comuns. Uma superclasse comum pode ser definida para que suas subclasses possam herdar tanto o
comportamento quanto a estrutura. A generalização é uma conveniência notacional que permite definir estrutura e
comportamento comuns em um só local e reutilizá-los onde for encontrado comportamento e estrutura repetidos. Consulte
Técnica: Generalização, para obter informações adicionais sobre relacionamentos de
generalização.
Ao encontrar uma generalização, crie uma superclasse comum para conter atributos, associações, agregações e operações
comuns. Remova o comportamento comum das classes que passarão a ser subclasses da superclasse comum. Defina um
relacionamento de generalização da subclasse para a superclasse.
|
Resolver Conflitos entre Casos de Uso
A finalidade desta etapa é evitar conflitos simultâneos causados quando há probabilidade de dois ou mais casos de uso
acessarem ao mesmo tempo as instâncias da classe de design, de maneira possivelmente inconsistente.
Uma das dificuldades de utilizar um caso de uso após o outro no processo de design é o fato de que dois ou mais casos
de uso podem tentar chamar operações simultaneamente nos objetos de design, de maneiras possivelmente conflitantes.
Nesses casos, os conflitos de simultaneidade devem ser identificados e resolvidos explicitamente.
Se o serviço de mensagens síncronas for utilizado, a execução de uma operação bloqueará as chamadas subseqüentes, até a
que a operação seja concluída. Serviço de mensagens síncronas implica uma ordem para o processamento das mensagens na
qual o primeiro a chegar é o primeiro a ser atendido. Isso poderá resolver o conflito de simultaneidade, principalmente
nos casos em que todas as mensagens têm a mesma prioridade ou quando cada mensagem é executada no mesmo encadeamento.
Nos casos em que um objeto pode ser acessado por diversos encadeamentos de execução (representados por classes ativas),
devem ser usados mecanismos explícitos para impedir ou resolver o conflito de simultaneidade.
Em sistemas de tempo real, nos quais os encadeamentos são representados pelo Produto de
Trabalho: Cápsulas, esse problema ainda aguarda uma solução para o acesso simultâneo múltiplo a objetos passivos,
enquanto as próprias cápsulas fornecem um mecanismo de enfileiramento e impõem a semântica de execução até a conclusão
para manipular o acesso simultâneo. A solução recomendada é encapsular os objetos passivos, evitando assim o problema
do acesso simultâneo através da semântica da própria cápsula.
É possível que diversas operações executadas no mesmo objeto sejam chamadas simultaneamente por encadeamentos de
execução distintos sem ocorrer conflito de simultaneidade; o nome e o endereço de um cliente podem ser modificados ao
mesmo tempo sem que haja conflito. O conflito só ocorre quando dois encadeamentos de execução diferentes tentam
modificar a mesma propriedade do objeto.
Para cada objeto que pode ser acessado simultaneamente por diversos encadeamentos de execução, identifique as seções de
código que precisam ser protegidas contra acesso simultâneo. No início da fase de Elaboração, será impossível
identificar segmentos de código específicos; as operações que devem ser protegidas serão suficientes. Em seguida,
selecione ou projete os mecanismos de controle de acesso apropriados para evitar o conflito devido ao acesso
simultâneo. Exemplos desses mecanismos incluem o enfileiramento de mensagens para serializar o acesso, o uso de
semáforos ou símbolos para permitir o acesso a apenas um encadeamento por vez ou outras variantes de mecanismos de
bloqueio. A escolha do mecanismo tende a ser altamente dependente de implementação e normalmente varia conforme a
linguagem de programação e o ambiente operacional. Consulte as Diretrizes Específicas do Projeto, para orientação ao selecionar
mecanismos de simultaneidade.
|
Manipular Requisitos Não Funcionais em Geral
As Classes de Design são refinadas para manipular requisitos gerais, não funcionais, Um dado inicial importante para
essa etapa são os requisitos não funcionais de uma classe de análise, que podem já estar declarados em seus requisitos
e responsabilidades especiais. Tais requisitos muitas vezes são especificados em termos dos mecanismos arquiteturais
(de análise) necessários para realizar a classe; nessa etapa, a classe é refinada para incorporar os mecanismos de
design correspondentes a esses mecanismos de análise.
Os mecanismos de design disponíveis são identificados e caracterizados pelo arquiteto de softwarePara cada mecanismo de
design necessário, qualifique quantas características puder, informando grupos quando possível. Consulte Tarefa: Identificar Mecanismos de Design, Conceito: Mecanismos de Análise e Conceito: Mecanismos de Design e de Implementação, para obter informações adicionais
sobre mecanismos de design.
Pode haver diversos mecanismos e diretrizes gerais de design que precisam ser considerados ao projetar classes, tais
como:
-
utilizar produtos e componentes existentes
-
adaptar-se à linguagem de programação
-
distribuir objetos
-
alcançar um desempenho aceitável
-
alcançar níveis de segurança específicos
-
tratar erros
|
Avaliar Seus Resultados
Verifique o modelo de design neste estágio para saber se seu trabalho está na direção certa. Não há necessidade de
revisar o modelo em detalhe, mas considere as seguintes listas de verificação:
|
|