• Nenhum resultado encontrado

4.1 Descrição das Diretrizes

4.1.8 D8 Adding Utility Operations

Objetivo: Evitar a repetição de expressões que servem para uma mesma finalidade e ocorrem mais de uma vez em restrições OCL de meta-classes.

Motivação: Quando estamos desenvolvendo meta-modelos muitas vezes utilizamos OCL para especificarmos restrições em meta-classes. Ao longo da meta-modelagem, pode ocorrer de precisarmos de uma mesma informação em restrições diferentes, isto é, uma mesma expressão OCL (ou até mesmo expressões definidas de maneiras diferentes) pode ser usada em diferentes partes do meta-modelo para uma mesma finalidade. Por exemplo, várias meta- classes do meta-modelo da UML precisam obter o limite máximo de uma multiplicidade (upperBound) para ser usado em suas restrições. Logo, se esta diretriz não for aplicada, a expressão OCL que obtém esta informação estará repetida em todas as meta-classes que a utilizam.

Dessa forma, o meta-modelo possuirá expressões OCL repetitivas e, muitas vezes, expressões diferentes que servem para o mesmo fim. Isto dificulta o seu entendimento e manutenção, pois se a expressão tiver que ser alterada, a modificação deverá ser feita em todas as restrições do meta-modelo que a definem. Além disso, o meta-modelo estará propício a erros devido às repetições e às diferentes formas de se definir as expressões.

Solução: A solução para evitarmos essa repetição de expressões nas restrições OCL do meta- modelo é criarmos uma operação adicional para cada expressão utilizada com freqüência. Caso tais operações possuam expressões apenas de consulta, sem causar nenhum efeito colateral, elas devem ser especificadas dentro de um definition (def). Por outro lado, se as operações possuírem expressões que causam efeitos colaterais, elas devem ser especificadas dentro de um postcondition (post). Portanto, esta diretriz sugere que ao invés de repetir a expressão em cada restrição OCL que a utiliza, tais restrições apenas devem invocar a operação adicional para obter a informação desejada.

Conseqüência: Haverá uma maior facilidade na manutenção e compreensão, uma vez que as expressões OCL úteis em várias partes do meta-modelo serão definidas apenas em um único local, nas operações. Por exemplo, se houver alguma mudança na expressão, ou seja, na forma de se obter o limite máximo de uma multiplicidade (upperBound), apenas a operação que obtém esta informação deverá ser alterada, e não todas as partes do meta-modelo que a utilizam. Outra vantagem é a diminuição da redundância e de erros que, possivelmente, poderiam ocorrer se o conjunto de restrições fosse definido nas diversas partes do meta- modelo, pois cada definição é independente e pode ser feita de formas diferentes. Além disso, as operações adicionais poderão ser reusadas em todo o meta-modelo, isto é, haverá um aumento do reuso.

Aplicabilidade: Pode ser aplicada em meta-modelos cujas restrições de algumas meta-classes possuam expressões OCL em comum, definidas de forma similar e para a mesma finalidade, isto é, quando há a repetição de expressões nas restrições do meta-modelo. A quantidade de aplicações da diretriz D8 é definida pelo número de operações adicionais criadas no meta- modelo com o intuito de evitar a repetição de expressões.

Diretrizes Relacionadas: Nenhuma.

Exemplo: Este exemplo mostra como a diretriz D8 deve ser aplicada no meta-modelo da UML. Vale salientar que algumas restrições OCL deste meta-modelo foram modificadas apenas para mostrar como seria um meta-modelo sem a utilização de operações utilitárias, pois, na realidade, ele já está em conformidade com a diretriz D8. No meta-modelo da UML, a restrição para obter o limite máximo de uma multiplicidade (upperBound) é útil em algumas de suas meta-classes, como MultiplicityElement, Property e ExtensionEnd. A seguir, vejamos como três restrições deveriam ser especificadas sem a utilização de uma operação adicional que obtenha o valor para o upperBound nestas três meta-classes, respectivamente:

[1] Especifica que uma multiplicidade deve definir, pelo menos, uma cardinalidade válida maior que zero. O atributo upper informa o limite máximo de multiplicidade, ele está

context MultiplicityElement

inv: let upperBound: UnlimitedNatural = if upper->notEmpty() then upper else 1 endif in upperBound->notEmpty() implies upperBound > 0

[2] Especifica que a multiplicidade do todo em uma associação de composição não deve ter um limite máximo maior que 1. Como Property estende a meta-classe

StructuralFeature, a qual estende MultiplicityElement, o atributo upper pode

ser usado por meio da herança.

context Property

inv: let upperBound: UnlimitedNatural = if upper->notEmpty() then upper else 1 endif in isComposite implies (upperBound->isEmpty() or upperBound <= 1)

[3] Especifica que a multiplicidade de um ExtensionEnd deve ser 0..1 ou 1. Como ExtensionEnd estende Property, o atributo upper pode ser usado por meio da herança.

context ExtensionEnd

inv: let upperBound: UnlimitedNatural = if upper->notEmpty() then upper else 1 endif in (self->lowerBound() = 0 or self->lowerBound() = 1) and upperBound = 1

Como podemos observar nas expressões em destaque das restrições 1, 2 e 3, o valor do upperBound é igualmente especificado e utilizado em todas elas. Portanto, como esta é uma informação útil em várias partes do meta-modelo, podemos criar uma operação adicional para obtê-la. Ela deve ser criada em MultiplicityElement, pois a informação obtida pertence à esta meta-classe. Vejamos como o meta-modelo da UML definiu tal operação, a qual retorna o limite máximo de uma multiplicidade:

context MultiplicityElement

def: upperBound() : UnlimitedNatural = if upper->notEmpty() then upper else 1 endif

Dessa forma, basta as restrições que necessitam desta informação invocarem a operação upperBound(), simplificando bastante o meta-modelo. Vejamos o resultado a seguir:

[1] context MultiplicityElement

inv: upperBound()->notEmpty() implies upperBound() > 0

[2] context Property

inv: isComposite implies (upperBound()->isEmpty() or upperBound() <= 1)

[3] context ExtensionEnd

inv: (self->lowerBound() = 0 or self->lowerBound() = 1) and upperBound() = 1

Neste exemplo, a diretriz D8 foi aplicada uma única vez, pois apenas a operação

upperBound() foi criada. Contudo, esta simples aplicação já nos leva a notar que a repetição

de algumas expressões OCL foi reduzida, o que refletiu diretamente em três restrições do meta-modelo.

A diretriz D8 pode ser aplicada em vários meta-modelos: (i) KobrA2 [Atkinson et al., 2009], em que meta-classes, tais como StructuralElement, ConstraintElement,

BehavioralElement e StructuralBehavioralElement, possuem restrições OCL

utilizando expressões em comum; e (ii) CHRD [Silva, 2009], em que a meta-classe

CHR::CHRD::Program::Rule possui quatro invariantes com expressões semelhantes, as

quais podem ser definidas em uma operação adicional.

Diretrizes para Definição de Valores Default

Neste tópico, serão apresentadas duas diretrizes que propõem uma melhoria nos meta- modelos a partir da definição de valores default: uma no escopo de atributos do tipo boolean e outra no escopo de enumerations.

Motivação: Quando estamos construindo a meta-classe de um meta-modelo, às vezes não paramos para observar os valores que seus atributos booleanos e seus enumerations podem assumir, de forma a tentarmos encontrar valores default caso nenhum valor seja informado para qualquer um destes elementos na instância da meta-classe. É importante definirmos valores default, principalmente, para atributos que nunca devem possuir valor nulo e sempre devem ter um valor associado caso nenhum seja informado, como é o caso dos atributos booleanos e dos enumerations.

Conseqüência: A utilização de valores default evitará que atributos tenham valores nulos, caso não seja definido nenhum valor no momento de sua instância. Além disso, vamos supor que a maioria das instâncias de uma meta-classe possui o mesmo valor para um determinado atributo. Logo, se definirmos este valor como default para o atributo, não será necessário defini-lo para cada instância da meta-classe.