Diretrizes: Pacote de Design
|
 Pacote de Design
|
Um pacote de design é um conjunto de classes, relacionamentos, realizações de casos de uso, diagramas e outros pacotes. Ele é usado para estruturar o modelo de design, dividindo-o em partes menores. Os pacotes são usados principalmente para a organização de modelos e geralmente servem como uma unidade de gerenciamento de configuração. |
Tópicos
O Modelo de Design pode ser estruturado em unidades menores para facilitar a compreensão. O agrupamento de elementos do Modelo de Design em pacotes e subsistemas, mostrando como esses agrupamentos estão relacionados entre si, é um procedimento que facilita a compreensão da estrutura geral do modelo. Lembre-se de que um subsistema de design é um tipo especial de pacote que possui uma semântica comportamental (ou seja, realiza uma ou mais interfaces). Para obter mais informações, consulte Artefato: Subsistema de Design e Diretrizes: Subsistema de Design. O objetivo de um subsistema de design difere do objetivo de um pacote de design, que é algo estático, um equivalente lógico do subsistema de implementação.
Uma classe contida em um pacote pode ser pública ou privada. Uma classe pública pode estar associada a qualquer outra classe. Uma classe privada pode ser associada apenas pelas classes contidas no pacote.
A interface de um pacote consiste nas classes públicas do pacote. A interface do pacote (classes públicas) isola e implementa as dependências existentes em outros pacotes. Isso simplifica o desenvolvimento paralelo, pois permite estabelecer interfaces com antecedência e os desenvolvedores só precisam saber das mudanças feitas nas interfaces de outros pacotes.
Há vários motivos para você particionar o Modelo de Design: - Os pacotes e os subsistemas podem ser usados como unidades de liberação, configuração ou pedido depois que o sistema estiver concluído.
- A alocação de recursos e a competência de diferentes equipes de desenvolvimento podem exigir que o projeto seja dividido entre vários grupos em locais distintos. Os subsistemas, com interfaces bem definidas, possibilitam a divisão do trabalho entre equipes de maneira controlada e coordenada, enquanto o design e a implementação prosseguem em paralelo.
- Os subsistemas podem ser usados para estruturar o modelo de design de forma a refletir os tipos de usuário. A origem de muitas mudanças de requisitos são os usuários. Os subsistemas garantem que as mudanças feitas por determinado tipo de usuário afetarão somente as partes do sistema correspondentes a esse tipo de usuário.
- Em alguns aplicativos, determinadas informações devem estar acessíveis somente para algumas pessoas. Os subsistemas permitem a manutenção do sigilo do usuário em áreas onde isso é necessário.
- Se estiver criando um sistema para suporte, você poderá usar subsistemas e pacotes para dar a ele uma estrutura semelhante à do sistema a ser suportado. Assim será possível sincronizar a manutenção dos dois sistemas.
- Os subsistemas servem para representar os produtos e serviços existentes usados pelo sistema (por exemplo, bibliotecas e produtos COTS), como explicado nas próximas seções.
Quando as classes de fronteira são distribuídas nos pacotes, duas estratégias diferentes podem ser aplicadas. A escolha da estratégia depende se as interfaces do sistema estão propensas a grandes mudanças no futuro. - Se houver a probabilidade de a interface do sistema ser substituída ou sofrer mudanças consideráveis, a interface deverá ser separada do resto do modelo de design. Quando a interface do usuário for alterada, somente esses pacotes serão afetados. Um exemplo desse tipo de mudança é trocar uma interface orientada por linhas por outra orientada por janelas.

Se o objetivo principal é simplificar as principais mudanças de interface, as classes de fronteira devem ser colocadas em um ou vários pacotes separados. - Caso não haja nenhuma grande mudança de interface planejada, as mudanças efetuadas nos serviços do sistema devem ser o princípio orientador. As classes de fronteira devem então ficar juntas com as classes de controle e de entidade com as quais elas estão relacionadas funcionalmente. Dessa forma, será fácil verificar quais classes de fronteira serão afetadas se uma classe de controle ou de entidade for alterada.

Para simplificar as mudanças efetuadas nos serviços do sistema, as classes de fronteira são empacotadas com as classes às quais estão relacionadas funcionalmente.
As classes de fronteira obrigatórias que não são relacionadas funcionalmente a qualquer classe de controle ou de entidade devem ser colocadas em pacotes separados, junto com as classes de fronteira que pertencem à mesma interface.
Se uma classe de fronteira estiver relacionada a um serviço opcional, agrupe-a com as classes que colaboram para oferecer o serviço em um subsistema separado. O subsistema fará o mapeamento para um componente opcional, que será fornecido quando a funcionalidade opcional for solicitada.
Um pacote deve ser identificado para cada grupo de classes relacionadas funcionalmente. Diversos critérios práticos podem ser aplicados para avaliar se duas classes estão relacionadas funcionalmente. São eles (por ordem decrescente de importância): - Se as mudanças efetuadas na estrutura e/ou no comportamento de uma classe exigirem mudanças em outra classe, as duas classes estão relacionadas funcionalmente.
Exemplo
Se um novo atributo for acrescentado à classe de entidade Pedido, é bem provável que a classe de controle Administrador de Pedidos precise ser atualizada. Portanto, elas pertencem ao mesmo pacote: Gerenciamento de Pedidos.
- Para saber se uma classe está relacionada funcionalmente a outra, comece com uma classe de entidade, por exemplo, e verifique qual será o impacto de removê-la do sistema. As classes que se passarem a ser supérfluas após a remoção da outra classe estão, de alguma forma, conectadas à classe removida. Definimos como supérflua a classe que só é usada pela classe removida ou que depende da classe removida.
Exemplo
O pacote Gerenciamento de Pedidos contém as duas classes de controle Administrador de Pedidos e Registrador de Pedidos, no Sistema de Administração de Depósito. As duas classes de controle modelam serviços referentes ao gerenciamento de pedidos feitos ao depósito. Todos os atributos e relacionamentos dos pedidos são armazenados pela classe de entidade Pedidos, que só existe para o gerenciamento de pedidos. Se a classe de entidade for removida, não haverá necessidade de manter o Administrador de Pedidos nem o Registrador de Pedidos, porque eles só são úteis para a classe Pedidos. Por isso, a classe de entidade Pedidos deve ser incluída no mesmo pacote das duas classes de controle.

Administrador de Pedidos e Registrador de Pedidos pertencem ao mesmo pacote Pedidos, pois passaram a ser supérfluos depois que Pedidos foi removido do sistema.
- Dois objetos podem estar relacionados funcionalmente se interagirem por meio de um grande número de mensagens ou se, pelo contrário, tiverem um sistema de intercomunicação complicado.
Exemplo
A classe de controle Executor de Tarefas e Interface do Transportador trocam muitas mensagens entre si. Essa é mais uma indicação de que elas devem ser incluídas no mesmo pacote: Gerenciamento de Tarefas.
- Uma classe de fronteira pode estar relacionada funcionalmente a determinada classe de entidade se a função da classe de fronteira for apresentar a classe de entidade.
Exemplo
A classe de fronteira Formulário de Plataforma de Carga, no Sistema de Administração de Depósito, apresenta uma instância da classe de entidade Plataforma de Carga ao usuário. Cada Plataforma de Carga é representada por um número de identificação na tela. Se as informações sobre a Plataforma de Carga forem alteradas (como, por exemplo, se Plataforma de Carga também receber um nome), a classe de fronteira talvez tenha de ser alterada. Formulário de Plataforma de Carga, portanto, deve ser incluída no mesmo pacote de Plataforma de Carga.
- Duas classes podem estar relacionadas funcionalmente se forem afetadas por mudanças no mesmo ator ou se interagirem com ele. Se as duas classes não envolverem o mesmo ator, elas não devem estar no mesmo pacote. Obviamente, a última regra poderá ser ignorada se houver motivos mais importantes.
Exemplo
O pacote Gerenciamento de Tarefas, no Sistema de Administração de Depósito, inclui a classe de controle Executor de Tarefas, entre outros itens. Esse é o único pacote envolvido com o ator Transportador, o responsável por transportar a plataforma de carga que está no depósito. O ator interage com a classe de controle Executor de Tarefas através da classe de fronteira Interface do Transportador. Essa classe de fronteira, portanto, deve ser incluída no pacote Gerenciamento de Tarefas.

Interface do Transportador e Executor de Tarefas pertencem ao mesmo pacote, pois ambas são afetadas pelas mudanças efetuadas no ator Transportador.
- Duas classes podem estar relacionadas funcionalmente se houver algum relacionamento entre elas (associações, agregações, etc.). Obviamente, esse critério não pode ser seguido sem um certo cuidado, mas pode ser adotado quando nenhum outro critério for aplicável.
- Uma classe pode estar relacionada funcionalmente à classe que cria instâncias da primeira.
Os seguintes critérios determinam quando duas classes não devem ser colocadas no mesmo pacote: - Duas classes que estejam relacionadas a atores diferentes não devem ser colocadas no mesmo pacote.
- Uma classe opcional e uma classe obrigatória não devem ser colocadas no mesmo pacote.
Primeiramente, todos os elementos de um pacote devem ter a mesma possibilidade de opção; não pode haver elementos de modelo opcionais em um pacote obrigatório.
Exemplo
A classe de entidade obrigatória Tipo de Artigo tem, entre outros itens, um atributo denominado Limite de Rearmazenamento. A função de rearmazenamento, contudo, é opcional no sistema. Por isso, Artigo deve ser dividido em duas classes de entidade, e a classe opcional deve se relacionar à classe obrigatória.
Um pacote considerado obrigatório pode não depender de qualquer pacote considerado opcional.
Como regra, um único pacote não pode ser usado por dois atores diferentes. O motivo para isso é que uma mudança no comportamento de um ator não deve afetar os outros atores. Há exceções a essa regra, como é o caso de pacotes que constituem serviços opcionais. Pacotes desse tipo não devem ser divididos, seja qual for o número de atores a utilizá-lo. Por isso, divida qualquer pacote (ou classe) que seja utilizado por diversos atores, a menos que o pacote seja opcional.
Todas as classes contidas no mesmo pacote devem estar relacionadas funcionalmente. Se você adotou os critérios descritos na seção "Localizar Pacotes de Classes Relacionadas funcionalmente", as classes de um pacote estarão relacionadas funcionalmente entre si. Contudo, uma determinada classe pode conter comportamentos ou relacionamentos "excessivos", que não pertençam à classe. Parte da classe deverá ser removida para se transformar em uma classe completamente nova ou em alguma outra classe, que provavelmente pertencerá a um outro pacote.
Exemplo
O comportamento de uma classe de controle A, contida em um pacote, não deve depender excessivamente da classe B, contida em outro pacote. Para isolar o comportamento específico de B, a classe de controle A deve ser dividida em duas classes de controle: A' e A". O comportamento específico de B é incluído na nova classe de controle A", que é inserida no mesmo pacote de B. A nova classe A" também recebe um relacionamento (generalização, por exemplo) com o objeto original A'.

Para isolar o comportamento específico de B, a classe de controle A, que não é homogênea, é dividida em duas classes de controle: A' e A''.
Se uma classe contida em um pacote estiver associada a uma classe em outro pacote, esses pacotes dependerão um do outro. As dependências de pacotes são modeladas usando o relacionamento de dependência existente entre os pacotes. Os relacionamentos de dependência ajudam a avaliar as conseqüências das mudanças. Um pacote do qual outros pacotes dependam é mais difícil de alterar do que um pacote que não possua dependências.
Como várias dependências desse tipo serão descobertas durante a especificação dos pacotes, esses relacionamentos deverão passar por mudanças durante o trabalho. A descrição de um relacionamento de dependência deve incluir informações sobre quais relacionamentos de classe causaram a dependência. Como esse procedimento apresenta informações difíceis de serem mantidas, ele só deve ser adotado se as informações forem pertinentes e importantes.
Exemplo
No Sistema de Administração de Depósito, há um relacionamento de dependência entre os pacotes Gerenciamento de Pedidos e Gerenciamento de Itens. Essa associação surge porque a classe de entidade Pedidos no Gerenciamento de Pedidos tem uma associação com a classe de entidade Tipo de Item no outro pacote.

O pacote Gerenciamento de Pedidos depende do Gerenciamento de Itens, porque há uma associação entre as duas classes nos pacotes.
O acoplamento de pacotes pode ser bom ou ruim. É bom por permitir reutilização, e ruim por representar as dependências que dificultam as mudanças e a evolução do sistema. Alguns princípios gerais podem ser seguidos: - Os pacotes não devem ser acoplados entre si (ou seja, não devem ser co-dependentes). Um pacote não deve depender de outro.

Nesses casos, os pacotes precisam ser reorganizados para remover as interdependências.
- Os pacotes de camadas inferiores não devem depender dos pacotes de camadas superiores. Só deve haver dependência entre pacotes que estejam na mesma camada e na camada inferior seguinte.

Nesses casos, a funcionalidade precisa ser reparticionada. Uma solução é definir as dependências em termos de interfaces e organizar as interfaces na camada inferior.
- Em geral, as dependências não devem ignorar as camadas, a menos que o comportamento dependente seja comum em todas as camadas. A alternativa é deixar as chamadas de operações atravessarem as camadas.
- Pacotes não devem depender de subsistemas, somente de outros pacotes ou de interfaces.
Copyright © 1987 - 2001 Rational Software Corporation
| |
|