Diretriz: Implementando Classes
Para implementar operações, é necessário:
- Escolher um algoritmo.
- Escolher estruturas de dados apropriadas aos algoritmos.
- Definir novas classes e operações, conforme necessário.
- Codificar a operação.
Escolher um Algoritmo
Várias operações são simples o suficiente para serem implementadas a partir da operação e
de sua especificação.
Os algoritmos incomuns são fundamentalmente necessários por duas razões:
implementar operações complexas para a qual uma especificação é fornecida e
otimizar operações para a qual um algoritmo simples mas eficiente serve como
definição.
Escolher Estruturas de Dados Apropriadas para os Algoritmos
A escolha de algoritmos envolve a escolha da estrutura de dados na qual funcionam.
Muitas estruturas de dados de implementação são classes do tipo contêiner, como matrizes, listas, filas, pilhas, conjuntos, pacotes e variações desses elementos.
A maioria das
linguagens orientadas a objetos e ambientes de programação fornece bibliotecas de classes
com esses tipos de componentes reutilizáveis.
Definir Novas Classes e Operações Conforme Necessário
Novas classes podem ser localizadas para receber resultados intermediários, por exemplo. Novas operações de
baixo nível podem ser incluídas na classe para decompor uma operação complexa. Em geral, essas operações são limitadas à classe, ou seja, não são
visíveis fora dela.
Codificar a Operação
Grave o código para a operação a partir da instrução de sua interface. Siga as
diretrizes de programação aplicáveis.
O estado de um objeto pode ser implementado por referência com os valores de seus
atributos, sem representação especial. As transições de estado desse objeto
estarão implícitas nas mudanças de valores dos atributos e os comportamentos variáveis
serão programados através de instruções condicionais.
Essa solução não é satisfatória para um comportamento complexo, pois geralmente
leva a estruturas complexas difíceis de serem alteradas conforme mais estados são
incluídos ou o comportamento é alterado.
Se o comportamento do elemento de design (ou de seus constituintes) for dependente do estado, haverá
normalmente um ou mais diagramas de gráfico de estado descrevendo o comportamento
dos elementos de modelo no elemento de design. Os diagramas
de estados funcionam como uma entrada importante durante a implementação.
As máquinas de estado mostradas em diagramas de gráfico de estado tornam o estado de um objeto explícito
e as transições e o comportamento requerido são claramente delineados. É possível implementar uma máquina de estado de diversas formas:
- para máquinas de estado simples, pela definição de um atributo que enumera os
possíveis estados e pela utilização do atributo para selecionar o comportamento de mensagens
que chegam. Por exemplo, em uma instrução de alternância, em Java ou C++. Essa solução não apresenta uma graduação precisa para máquinas de estado complexas e poderá levar ao desempenho precário de tempo de execução.
Consulte [DOUG98], Capítulo 4, 4.4.3 para obter
um exemplo desse método
- para máquinas de estado mais complexas, o padrão de Estado poderá ser usado.
Consulte [GAM94] para obter uma descrição do padrão
de Estado. [DOUG98], Capítulo 6, 6.2.3, Padrão
de Estado, também descreve essa abordagem
- uma abordagem baseada em tabelas é eficaz para máquinas de estado muito complexas, nas quais a facilidade de fazer mudanças é um critério.
Nesta abordagem, há entradas para cada
estado em uma tabela, em que cada entrada mapeia entradas para estados bem-sucedidos e ações de
transição associadas. Consulte [DOUG98], Capítulo
6, 6.2.3, Padrão de Tabela de Estado, para obter um exemplo desse método.
As máquinas de estado com subestados coincidentes podem ser implementadas pela delegação de gerenciamento
de estado a objetos ativos, um para cada subestado coincidente, porque os subestados
coincidentes representam cálculos independentes (que podem, contudo, interagirem). É possível gerenciar cada subestado usando uma das técnicas descritas
anteriormente.
Se uma classe ou partes de uma classe puderem ser implementadas pela reutilização de uma classe existente,
utilize a delegação em vez da herança.
A delegação significa que a classe é implementada com a ajuda de outras classes.
A classe faz referência a um objeto de outra classe usando uma variável.
Quando uma operação é chamada, ela chama uma operação no objeto referenciado (da
classe reutilizada) para execução real. Portanto, ela delega responsabilidade para a
outra classe.
Uma associação unidirecional é implementada como um ponteiro - um atributo que contém uma referência a objeto.
Se a multiplicidade for única, ela será implementada
como um ponteiro simples. Se for muitas, ela será um conjunto de ponteiros. Se a extremidade muitas for solicitada, então, uma lista poderá ser reutilizada no lugar
de um conjunto.
Uma associação bidirecional é implementada como atributos nos dois sentidos, usando técnicas das associações unidirecionais.
Uma associação qualificada é implementada como uma tabela de pesquisa (por exemplo, uma classe Smalltalk Dictionary) no objeto qualificador.
Os valores do seletor na tabela de pesquisa são os qualificadores e os valores-alvo são os objetos da outra classe.
Se for necessário acessar os valores dos qualificadores ordenadamente, você poderá organizar os qualificadores em uma matriz classificada ou uma árvore.
Nesse caso, o tempo de acesso será proporcional ao log N, onde N é o número dos valores dos qualificadores.
Se os qualificadores forem obtidos de um conjunto limitado compacto, os valores correspondentes poderão ser mapeados para um intervalo inteiro e a associação poderá ser implementada de forma eficiente como uma matriz.
Esta abordagem será mais atraente se a associação estiver cheia em sua maior parte,
em vez de escassamente preenchida e será ideal para conjuntos finitos totalmente preenchidos.
A maioria das linguagens orientadas a objetos e ambientes de programação fornece bibliotecas de classes com componentes reutilizáveis para implementar diferentes tipos de associações.
Implemente os atributos de uma de três maneiras: utilize tipos originais
internos, utilize uma classe existente ou defina uma nova classe. A definição de uma nova classe costuma ser mais flexível, mas inclui procedimentos indiretos desnecessários.
Por exemplo, o número do INSS de um funcionário pode ser implementado como um atributo do
tipo Seqüência de caracteres ou como uma nova classe.

Implementações alternativas de um atributo.
Também pode ser o caso de grupos de atributos serem reunidos em novas classes, como mostra o exemplo a seguir.
As duas implementações estão corretas.

Os atributos em Linha são implementados como associações a uma classe Ponto.
|