Conceitos: Mecanismos de Design e Implementação
Tópicos
O mecanismo de design é um refinamento de um mecanismo de análise correspondente (consulte também Conceitos: Mecanismos de Análise). Um mecanismo de design acrescenta detalhes concretos ao mecanismo de análise conceitual, mas quase não exige tecnologia específica. Suponhamos, por exemplo, a implementação de um sistema de gerenciamento de banco de dados orientado a objetos feita por um fornecedor específico. Assim como acontece com os mecanismos de análise, um mecanismo de design pode instanciar um ou mais padrões, nesse caso os padrões de design ou de arquitetura.
Da mesma forma, um mecanismo de implementação é um refinamento de um mecanismo de design correspondente, utilizando, por exemplo, uma linguagem de programação específica e uma tecnologia de implementação diferente (como um produto personalizado de um determinado fornecedor). Um mecanismo de implementação pode instanciar um ou mais idiomas ou padrões de implementação.
Considere o mecanismo de análise de Persistência:
- Talvez seja necessário armazenar vários (2.000) objetos pequenos (de 200 bytes cada um) por alguns segundos, sem nenhuma necessidade de permanência.
- Talvez seja necessário armazenar permanentemente no disco vários objetos muito grandes por vários meses, objetos que nunca serão atualizados, mas que precisarão ser armazenados com meios sofisticados de recuperação.
Esses objetos exigirão um suporte diferente à persistência. As seguintes características dos mecanismos de design para suporte à persistência poderão ser identificadas:
- Armazenamento na memória; características: um total de 1 MB, no máximo (tamanho x volume); acesso muito rápido para leitura, gravação e atualização.
- Placa flash; características: um máximo de 8 MB; acesso lento para atualização e gravação; acesso moderado para leitura.
- Arquivo binário; características: de 100 KB a 200 MB; acesso lento para atualização; acesso lento para leitura e gravação.
- Sistema de Gerenciamento de Banco de Dados (DBMS); características: a partir de 100 KB (basicamente sem limite superior); acesso ainda mais lento para atualização, leitura e gravação.
Observe que essas velocidades somente são classificadas como 'lenta' em relação ao armazenamento na memória. Obviamente, em alguns ambientes, o uso do cache pode melhorar os tempos de acesso aparentes.

Inicialmente, o mapeamento entre os mecanismos de design e os mecanismos de implementação provavelmente não será ideal, mas manterá o projeto em execução, identificará os riscos ainda não observados e disparará posteriormente investigações e avaliações. À medida que o projeto continuar e ganhar mais conhecimento, o mapeamento precisará ser refinado.
Proceda iterativamente para refinar o mapeamento entre os mecanismos de design e de implementação, eliminando os caminhos redundantes, trabalhando tanto "de maneira direcionada" como "de maneira não direcionada".
Trabalho de Maneira Direcionada. Quando o trabalho é feito "de maneira direcionada", as realizações de caso de uso novas e refinadas imporão novos requisitos aos mecanismos de design necessários por meio dos mecanismos de análise necessários. Esses novos requisitos podem revelar características adicionais de um mecanismo de design, forçando uma divisão entre os mecanismos. Existe também um comprometimento entre a complexidade do sistema e seu desempenho:
- Uma grande quantidade de mecanismos de design diferentes torna o sistema bastante complexo.
- Uma pequena quantidade de mecanismos de design pode gerar problemas de desempenho para alguns mecanismos de implementação que aumentam os limites dos intervalos aceitáveis de seus valores de característica.
Trabalho de Maneira Não Direcionada. Quando o trabalho é feito "de maneira não direcionada", investigando os mecanismos de implementação disponíveis, você pode encontrar produtos que satisfaçam a vários mecanismos de design de uma só vez, mas forçará uma certa adaptação ou reparticionamento dos mecanismos de design. Você quer minimizar o número de mecanismos de implementação utilizados, mas ter uma pequena quantidade de mecanismos pode gerar problemas de desempenho.
Depois que você decidir usar um DBMS para armazenar objetos de classe A, provavelmente se verá tentado a utilizá-lo para armazenar todos os objetos do sistema. Essa prática pode se revelar bastante ineficaz ou bastante inconveniente. Nem todos os objetos que exigem persistência precisam ser armazenados no DBMS. Alguns objetos podem ser persistentes, mas podem ser freqüentemente acessados pelo aplicativo e raramente acessados por outros aplicativos. Adotar uma estratégia híbrida em que o objeto seja lido do DBMS para a memória e periodicamente sincronizado pode ser a melhor abordagem.
Exemplo
Um vôo pode ser armazenado na memória para fins de acesso rápido e em um DBMS para fins de persistência a longo prazo. No entanto, isso disparará a necessidade de um mecanismo sincronizar ambos.
É comum ter mais de um mecanismo de design associado a uma classe cliente como indício de um comprometimento entre as diferentes características.
Como os mecanismos de implementação são geralmente fornecidos em pacotes de componentes (sistemas operacionais e produtos personalizados) desenvolvidos internamente e adquiridos prontos para serem usados, será necessária uma certa otimização baseada no custo, uma desproporção de impedância ou uma uniformidade de estilo. Além disso, os mecanismos são geralmente interdependentes, o que dificulta a separação clara dos serviços em mecanismos de design.
Exemplos
O refinamento continua no decorrer de toda a fase de elaboração e representa sempre um comprometimento entre:
- Uma 'adequação' exata aos requisitos dos clientes do mecanismo de design, no que diz respeito às características esperadas.
- O custo e a complexidade decorrentes da grande quantidade de mecanismos de implementação a serem obtidos e integrados.
A meta geral é sempre ter um conjunto simples de mecanismos que proporcionem a um sistema grande integridade conceitual, simplicidade e elegância.
Os mecanismos de design de Persistência podem ser mapeados para os mecanismos de implementação da seguinte maneira:

Um possível mapeamento entre os mecanismos de análise e os mecanismos de design. As setas pontilhadas significam "é especializado por", implicando que as características dos mecanismos de design são herdadas dos mecanismos de análise, mas que elas serão especializadas e refinadas.
Depois que você tiver terminado de otimizar os mecanismos, estes serão os mapeamentos resultantes:

As decisões de design para uma classe cliente em termos de mapeamentos entre mecanismos. A classe Flight precisa de duas formas de persistência: armazenamento na memória implementado por uma rotina de biblioteca pronta para uso e um banco de dados implementado com um produto ObjectStorage desenvolvido internamente e adquirido pronto para ser usado.
O mapa deve ser navegável em ambas as direções, para que seja fácil determinar as classes cliente quando os mecanismos de implementação forem alterados.
Os mecanismos de design e os detalhes referentes ao seu uso estão documentados em Artefato: Guias de Design. O relacionamento (ou mapeamento) entre os mecanismos de análise, de design e de implementação, e os fundamentos associados dessas alternativas, estão documentados em Artefato: Documento de Arquitetura de Software.
Assim como acontece com os mecanismos de análise, os mecanismos de design podem ser modelados por meio de uma colaboração, que pode instanciar um ou mais padrões de design ou de arquitetura.
Exemplo: Um Mecanismo de Persistência
Este exemplo usa uma instância de um padrão de persistência baseada em RDBMS delineado da JDBC(tm) (Java Data Base Connectivity, Conectividade de Banco de Dados Java). Embora apresentemos o design aqui, a JDBC fornece o código real de algumas classes. Portanto, você está a um passo de um mecanismo de implementação.
A figura Visão Estática: a JDBC mostra as classes (estritamente, os papéis do classificador) da colaboração.
Visão Estática: JDBC
As classes que aparecem em amarelo são as fornecidas, ao passo que as outras (myDBClass etc.) foram vinculadas pelo designer para criar o mecanismo.
Com a JDBC, um cliente trabalhará com uma DBClass para ler e gravar dados persistentes. A DBClass está encarregada de acessar o banco de dados JDBC usando a classe DriverManager. Depois que um banco de dados Connection estiver aberto, a DBClass poderá criar instruções SQL que serão enviadas ao RDBMS básico e executadas por meio da classe Statement. A classe Statement é a que "fala" com o banco de dados. O resultado da consulta SQL retorna em um objeto ResultSet.
A classe DBClass é responsável por tornar uma outra instância de classe persistente. Ela compreende o mapeamento OO-para-RDBMS e faz a interface com o RDBMS. A DBClass nivela o objeto, grava-o no RDBMS, lê os seus dados no RDBMS e cria o objeto. Cada classe persistente terá uma DBClass correspondente.
A PersistentClassList é usada para retornar um conjunto de objetos persistentes como resultado de uma consulta de banco de dados (por exemplo, DBClass.read()).
Agora, apresentaremos uma série de visões dinâmicas, a fim de mostrar como o mecanismo realmente funciona.
JDBC: Inicializar
A inicialização deve ocorrer antes que qualquer classe persistente possa ser acessada.
Para inicializar a conexão com o banco de dados, a DBClass deve carregar o driver apropriado chamando a operação getConnection() da classe DriverManager com um URL, um usuário e uma senha.
A operação getConnection() tenta estabelecer uma conexão com um determinado URL de banco de dados. A DriverManager tenta selecionar um driver apropriado no conjunto de drivers JDBC registrados.
Parâmetros:
url: um URL de banco de dados no formato jdbc:subprotocol:subname. Esse URL é usado para localizar o servidor de banco de dados real e não está relacionado à Web nesta instância.
user: o usuário de banco de dados em cujo nome a conexão está sendo estabelecida.
pass: A senha do usuário
Retorna:
uma conexão com o URL.
JDBC: Criar
Para criar uma nova classe, o cliente de persistência solicita à DBClass que crie a nova classe. A DBClass cria uma nova instância de PersistentClass com valores padrão. Em seguida, ela cria uma nova instrução usando a operação createStatement() da classe Connection. A instrução é executada e os dados são inseridos no banco de dados.
JDBC: Ler
Para ler uma classe persistente, o cliente de persistência solicita à DBClass que execute a leitura. A DBClass cria uma nova instrução usando a operação createStatement() da classe Connection. A instrução é executada e os dados são retornados em um objeto ResultSet. Em seguida, a DBClass cria uma nova instância da PersistentClass e a preenche com os dados recuperados. Os dados são retornados em um objeto de coleção, uma instância da classe PersistentClassList.
Observação: A seqüência de caracteres transmitida para executeQuery() não é necessariamente idêntica a que foi passada para read(). A DBClass criará a consulta SQL para recuperar os dados persistentes do banco de dados, usando os critérios passados para read(). Isso acontece porque não queremos que o cliente da DBClass precise do conhecimento dos internos do banco de dados para criar uma consulta válida. Esse conhecimento fica encapsulado dentro da DBClass.
JDBC: Atualizar
Para atualizar uma classe, o cliente de persistência solicita que a DBClass execute a atualização. A DBClass recupera os dados do objeto PersistentClass fornecido e cria uma nova instrução usando a operação createStatement() da classe Connection. Depois que a instrução é criada, a atualização é executada e o banco de dados é atualizado com os novos dados da classe.
Lembre-se: É função da DBClass "nivelar" a PersistentClass e gravá-la no banco de dados. É por isso que ela deve ser recuperada a partir da PersistentClass específica antes da criação da instrução SQL.
Observação: No mecanismo acima, a PersistentClass deve fornecer rotinas de acesso a todos os dados persistentes, a fim de que a DBClass possa acessá-las. Isso permite o acesso externo a determinados atributos persistentes que, do contrário, teriam sido privados. Esse é o preço que você deve pagar para arrancar o conhecimento de persistência da classe que encapsula os dados.
JDBC: Excluir
Para excluir uma classe, o cliente de persistência solicita à DBClass que exclua a PersistentClass. A DBClass cria uma nova instrução usando a operação createStatement() da classe Connection. A instrução é executada e os dados são removidos do banco de dados.
Na implementação desse design, algumas decisões serão tomadas no que diz respeito ao mapeamento da DBClass para as classes persistentes como, por exemplo, ter uma DBClass por classe persistente e alocá-las nos pacotes apropriados. Esses pacotes dependerão do pacote java.sql fornecido (consulte JDBC(tm) API Documentation) que contém as classes de suporte DriverManager, Connection, Statement e ResultSet.
Copyright
(c) 1987 - 2001 Rational Software Corporation
|