Você está na página 1de 93

Apuntes de prácticas de Diseño

de Sistemas Software

Contenidos

!  Guía
práctica 1. Object Constraint
Language (OCL)
!  Guía práctica 2. La vista lógica

2
Guía práctica 1. OCL
Object Constraint Language

OCL
!  Cuando diseñamos un sistema OO, es necesario especificar un conjunto de
restricciones semánticas:
"  utilizar lenguaje natural conduce a ambiguedades

"  no a todos les resulta familiar utilizar métodos formales

"  UML no cuenta con la expresividad suficiente para modelar muchas


restricciones

!  Debido a estas razones ha surgido OCL:

"  permite describir restricciones (expresiones) sobre modelos UML


"  permite definir y documentar modelos UML en forma más precisa

"  Es un lenguaje tipado, libre de efectos laterales

4
OCL
!  OCL es un lenguaje declarativo: a partir del cual se
establece que debe ser hecho por el sistema, y no
como debe ser hecho

!  OCL es un lenguaje tipado. Todas las expresiones (y


sus subexpresiones) tienen un tipo y se requiere
conformidad de tipo

!  La clave de especificar modelos precisos, completos,


detallados y consistentes es la construcción de
modelos UML/OCL combinados
5

Usos de OCL
Ejemplos de su utilidad:
!  Complementar diagramas UML: diagramas de clase, diagrama de
transición de estados, diagramas de actividades, etc
!  Expresar la semántica de UML
!  Especificar reglas de negocio

!  Definir precisamente métricas para modelos UML


!  Definir precisamente estereotipos

Especificación de OCL Versión 2.0 (documento de OMG):

http://www.omg.org/docs/ptc/03-10-14.pdf

6
Conceptos Invariantes
básicos de OCL Pre- y Post-
condiciones
Instancia contextual
navegaciones

Expresiones OCL
En OCL es posible especificar expresiones OCL.

Existen dos tipos básicos de expresiones OCL: invariantes, y


pre-/post-condiciones
esto es útil en diseño por contratos

Antes de dar ejemplos de ambas, necesitamos introducir, al


mismo tiempo, otros conceptos básicos utilizados en una
expresión OCL

!  Cada expresión OCL está escrita en el contexto de una


instancia de un tipo específico (self)

8
invariantes
!  Un invariante es una condición que debe ser verdadera para todas las
instancias de un tipo específico en cualquier momento
!  El tipo de la instancia contextual de una expresión OCL, el cual es parte de
una invariante, es escrito luego de la palabra reservada context.
!  La palabra reservada inv: declara que la expresión OCL es una restricción
invariante

"  Ejemplo de un invariante: Habitación


número_piso : Integer
context Habitación número_habitación : Integer
número_de_camas : Integer
tipo : {A, B}
inv: self.número_de_camas <= 10

Instancia contextual
! Cada expresión OCL está escrita en el contexto de una instancia de un tipo
específico.
! La palabra reservada self es utilizada para referir a la instancia contextual.
context Habitación

inv: self.número_de_camas <= 10 Habitación


número_piso : Integer
número_habitación : Integer
número_de_camas : Integer
tipo : {A, B}
context Habitación

inv: número_de_camas <= 10

Alternativamente en lugar de self es posible definir un nombre que represente


el rol de self
context h: Habitación

inv: h.número_de_camas <= 10

10
Ejemplo de invariante
<<enumeration>>
Genero
mCuentas Masculino
Cuenta femenino
0..*
mTitulares /msaldo: Real
1..*
! Cliente
mCuentaNómina
mNombre: String
0..* Movimiento
mApellidos: String
mImporte: Real
mEdad: Integer mCuentaAsociada
mMovs mConcepto: String
Sexo: Genero
mFecha: Fecha
1 mtitular
0..*
mMovs

Fecha
mtarjetas 0..* <<datatype>>
mDia: Integer
Tarjeta mMes: Integer
MNombreTitular: String mAño: Integer
ObtenerMes(d: Fecha) : Integer

La edad de cualquier cliente es siempre mayor o igual a cero

context Cliente

inv: mEdad>=18
11

Pre y post condiciones

!  Una precondición /postcondición es una condición que debe ser


verdadera antes /después de la ejecución de una operación.

!  La instancia contextual self es una instancia del tipo que es dueño de


la operación.

!  La declaración incluye la palabra context, seguida del contexto y de la


declaración de la operación y el tipo.

!  Las etiquetas pre y post declaran si se trata de una pre/postcondición.

12
Pre y post condiciones
context Empleado::aumentarsalario( cantidad: Real ): Real
pre: salario > 0

post: self.salario = self.salario@pre + cantidad and


result = self.salario

!  En una postcondición, nos podemos referir a los valores de cada propiedad


de un objeto en dos momentos en el tiempo:
"  El valor de la propiedad al comienzo de la operación o método (utilizamos
el postfijo @pre)
"  El valor de la propiedad una vez que la operación o método se ha
ejecutado.

Nota: ‘@pre’ solo se permite en expresiones del tipo postcondicion !

13

Navegaciones y
colecciones
Navegaciones Simples

context Habitación
inv: self.huespedes->size() <= self.número_de_camas

! Una relación es navegada cuando se utiliza en una expresión...

"  el nombre de rol (del extremo opuesto de una relación) que vincula
la clase donde se define la expresión con otra clase del diagrama.

15

Navegaciones Simples

context Habitación
inv: self.Huesped->size() <= self.número_de_camas

Habitación
Huésped
número_piso : Integer
* nombre : String
número_habitación : Integer
edad : Integer
número_de_camas : Integer
sexo : {hombre, mujer}
tipo : {A, B}

Una relación es navegada cuando se utiliza en una expresión...

"  el nombre de una clase (si el modelador ha omitido el nombre de


rol de la asociación).

16
Colecciones
!  El tipo Collection es un tipo abstracto, con tipos de
colección concretos como sus subtipos.

"  Set (Conjunto), Java type / Concrete Type


"  OrderedSet (Conjunto ordenado) –  Set / HashSet
"  Bolsa (Bag) –  List / ArrayList
"  Sequences (Secuencias) –  List / ArrayList

–  List / ArrayList

context Habitación
inv: self.Huesped->size() <= self.número_de_camas

17

Navegaciones combinadas
Las navegaciones no se limitan a una única asociación.

Las expresiones OCL pueden estar encadenadas navegando un conjunto


de asociaciones

context Vuelo

inv: self.avion.tipo.cant_de_asientos >= self.pasajeros->size()

18
Navegaciones y Colecciones

Los tipos de colecciones juegan un importante rol en las


expresiones OCL !

"  Una única navegación resulta en un conjunto (Set),

"  navegaciones combinadas en un Bag,

"  navegaciones sobre asociaciones adornadas con {ordered}


resultan en un OrderedSet.

19

Navegando a Clases de Asociación

!  Para especificar la navegación a clases de asociación, OCL utiliza un


punto y el nombre de la clase de asociación comenzando con un
carácter en minúscula

context Persona

inv: self.job ....

20
Navegando desde
clases de Asociación

Es posible navegar desde la clase de asociación a los objetos que


participan en la asociación.

context job

inv: self.empleado.edad > 21

21

Valores Básicos y
Tipos
Tipos Básicos
!  En OCL, se definen un número de tipos básicos, los cuales están disponibles
para el modelador en todo momento. Estos tipos son valores predefinidos y son
independientes de cualquier modelo de objetos.

!  Tipos Básicos:
" Boolean: true, false

" Integer :1, -5, 2, 34, 26524, ...

" Real: 1.5, 3.14, ...

" String: ‘ser o no ser...‘

" Colecciones: (definidas posteriormente)

!  Operaciones definidas en los tipos


" Integer: *, +, -, /, abs(), etc.

" Real: *, +, -, /, etc.

" Boolean: and, or, xor, not, implies, if-then-else-endif

" String: concat(), size(), substring()

23

Tipos Básicos

!  Cada expresión OCL se escribe en el contexto de un modelo UML.

!  En UML un classifier es una clase, o una interfaz, un tipo de dato.

!  Todos los classifiers de un modelo UML son tipos que pueden ser
utilizados en las expresiones OCL que estén asociadas a dicho
modelo.

24
Tipos Enumerados

Las enumeraciones son tipos de datos en UML y tienen un nombre. Una


enumeración define un número de literales, que son valores posibles
de la enumeración.

En OCL podemos referirnos a los valores de una enumeración.

context Persona inv: genero = Genero::masculino

Persona <<enumeration>>
nombre : String Genero
edad : Integer masculino
genero : Genero femenino

25

Conformidad de tipos

OCL es un lenguaje tipado.


Una expresión OCL en el cual todos los tipos son conformes (es decir hay
conformidad de tipos) es una expresión válida.

sino existirá un Error de conformidad de tipo!!

1 + ‘motocicleta’
23 * falso

Un tipo es conforme con su(s) supertipo(s)

Herramientas: IBM parser, Dresden Toolkit, TU Munich Tool, ModelRun,


Bremer USE

26
Más sobre Conformidad de tipos

Los tipos Set(X), Bag(X) y Sequence(X) son todos subtipos de


Collection(X)
Reglas de conformidad de tipos:

!  Type1 es conforme a Type2 cuando ellos son idénticos!


• Type1 es conforme a Type2 cuando Type1 es un subtipo de Type2!
• Collection(Type1) es conforme a Collection(Type2), cuando Type1 es
conforme a Type2. Esto es verdadero para!
Set(Type1)/Set(Type2), Sequence(Type1)/Sequence(Type2),
Bag(Type1)/Bag(Type2)!
• La conformidad de tipo es transitiva!

27

Más sobre Conformidad de tipos

Ejemplo:

Si Bicycle y Car son dos subtipos de Transport entonces:

Set(Bicycle) es conforme a Set(Transport)

Set(Bicycle) es conforme a Collection(Bicycle)

Set(Bicycle) es conforme a Collection(Transport)

Ejemplo:

Set(Bicycle) NO es conforme a Bag(Bicycle)

28
Profundizando algunos
Propiedades:
conceptos de OCL
• atributos
• operaciones
• extremos finales
de una asociación

Objetos y Propiedades

!  Una propiedad es:

" Un atributo

" Un extremo de asociación

" Una operación/método libre de efectos laterales

!  Una operación o método se define como libre de efectos laterales si no modifica


el estado del sistema

!  Notación “Punto”:El valor de una propiedad en un objeto se especifica en una


expresión OCL con un punto seguido del nombre de la propiedad

<<invariant>>
Cliente
mNombre: String
mApellidos: String self.mEdad >= 17
mEdad: Integer
lim_max_mov:Integer

30
Propiedades: Atributos

!  Por ejemplo, la siguiente expresión OCL: “la edad de cliente es


mayor o igual a 17 años”:

context Cliente Cliente


mNombre: String
mApellidos: String
inv: self.mEdad >= 17 mEdad: Integer
lim_max_mov:Integer

El valor de la subexpresión self.mEdad es el valor de mEdad en la


instancia particular de Cliente identificada por self.
El tipo de la subexpresión self.mEdad es el tipo del atributo
mEdad, que es un tipo Integer estándar.

31

Propiedades: Operaciones

!  Para referirnos a una operación o método que no tiene parámetros, se


requiere especificar una lista vacía de argumentos:

Context Producto

Inv: self.obtenerprecio() > 0

32
Propiedades: Extremos finales de
asociaciones

!  A partir de un objeto específico, es posible navegar una asociación en el diagrama de


clase para referirnos a otros objetos y sus propiedades.

objeto.nombredelextremoFinal

!  El valor de la subexpresión es un objeto o conjuntos de objetos, dependiendo de la


multiplicidad del extremo final de la asociación.
context Compañia

inv: self.gerente.esDesocupado = false

inv: self.empleados->notEmpty()

!  En self.empleados->notEmpty() estamos accediendo a la propiedad notEmpty en el


conjunto self.empleados.
33

Combinando propiedades

!  Las propiedades se pueden combinar para escribir expresiones más


complejas.

!  Una regla importante es que una expresión OCL siempre se evalúa a


un objeto específico de un tipo especifico. Luego de obtener el
resultado, es posible aplicar otra propiedad para obtener un nuevo
resultado.

!  Cada expresión OCL puede ser leída y evaluada de izquierda a


derecha.

context Cliente

inv: self.lim_max_mov >= self.cuentas.mMovs->asSet()->size()

Cliente
Cuenta Movimiento
mNombre: String 0..*
0..*
mTitulares /msaldo: Real mImporte: Real
mApellidos: String
1..* cuentas mMovs mConcepto: String
mEdad: Integer
mFecha: Date
lim_max_mov:Integer

34
Colecciones y
operaciones de Colecciones:
colección Set, orderedset, bag,
sequence, etc.
Operaciones colección:
Select, Reject, Exists,
etc.

Colecciones

!  Siempre que una navegación resulta en una colección de objetos


podemos utilizar operaciones de colección para manipular la colección.

!  El tipo Collection es un tipo predefinido en OCL. El tipo esta definido


en conjunto con operaciones predefinidas.

!  Las operaciones de colección nunca modifican las colecciones.

!  Nota: Una lista (incompleta) de operaciones de colección se puede


encontrar en las tablas 1-4 ....
!  Hay dos formas de obtener colecciones, a partir de un literal o a partir de
navegaciones.
"  Ejemplo de un literal conjunto: Set {1, 2, 3, 5}

36
Operaciones de Colecciones
!  OCL define muchas operaciones en tipos de colección. Estas
operaciones permiten contar con una manera flexible y poderosa de
proyectar nuevas colecciones desde colecciones existentes.

!  Notación flecha “->”:

colección->operaciónDeColeccion()
!  Las operaciones son:

"  Select y Reject.


"  Collect

"  ForAll
"  Exists

"  Includes
"  etc
37

Operador Select

!  A veces estamos interesados solo en un subconjunto específico de una


colección. OCL tiene constructores especiales para especificar una selección de
una colección. Estos operadores son Select y Reject.

!  select es una operación sobre una colección y es especificada utilizando la


sintaxis de flecha:

collection->select( expresión booleana)

!  El resultado es una colección que contiene todos los elementos de la colección


origen para los cuales es verdadera la expresión booleana.

!  Para encontrar el resultado de esta operación, se evalúa la expresión para


cada elemento de la colección. Si el resultado de la evaluación es verdadero
para un elemento, este se incluye en la colección resultante.

38
Operador Select (cont.)

context Proyecto

inv: self.participa -> select (edad > 50) ->notEmpty()

!  El contexto de la expresión en el argumento select es el del elemento de la colección en el


cual el select es invocado.

context Proyecto

inv: self.participa-> select (e: Empleado | e.edad > 50) ->notEmpty()

context Proyecto

inv: self.participa-> select (e | e.edad > 50) ->notEmpty()

39

Forma general de especificar


las operaciones de colección

colección->operación( v: Type | expresión-booleana-utilizando-v )

colección->operación( v | expresión-booleana-utilizando-v )

colección->operación( expresión-booleana)
“ v ” un iterador, es una referencia a los objetos en la colección

40
Operador Reject

!  El operador reject permite obtener un subconjunto de todos los elementos de


una colección para el cual la expresión se evalúa a falso.

context Proyecto

inv: self.participa -> reject ( esCasado ) ->isEmpty()


" La colección de las personas que no están casadas es vacía.

41

Operador collect

!  El operador collect se utiliza cuando queremos derivar una nueva colección a


partir de otra, pero que contiene objetos diferentes de la colección original.

self.empleados->collect( fechaNacimiento )

self.empleados->collect( emp : Empleado | emp.fechaNacimiento )

!  La colección resultante no es un conjunto es un bag.

Para convertir el bag en un set:

self.empleados->collect( fechaNacimiento )->asSet()

42
Forma resumida de collect

Existe una forma resumida de escribir la operación collect y que hace que las
expresiones OCL sean mas fáciles de leer.

En lugar de escribir: self.empleados->collect( fechaNacimiento )

es posible escribir: self.empleados.fechaNacimiento

43

Operación ForAll

!  Este operador permite especificar una expresión booleana que debe ser verdadera para
todos los elementos de una colección.

!  La exp. forAll tiene como resultado un valor booleano.

context Proyecto

inv: self.empleados->forAll( p: Empleado | p.edad <= 65)

44
Operación ForAll

El operador forAll tiene una variante extendida en el cual mas de un iterador es


utilizado. Ambos iteradores iterarán sobre la colección completa. Efectivamente
esto constituye el operador forAll en el producto cartesiano de la colección.

context Proyecto

inv: self.empleados-> forAll (e1, e2: Empleado | e1<> e2 implies


e1.apellido <> e2.apellido)

45

Operación Exists

!  Muchas veces es importante saber si al menos para un elemento de una


colección se verifica una condición:

context Proyecto

inv: self.empleados->exists( p | p.nombre = ‘Jack’)

46
Ejemplo de la operación exists
<<enumeration>>
Genero
mCuentas Masculino
Cuenta femenino
0..*
mTitulares /msaldo: Real
1..*
Cliente
mNombre: String mCuentaNómina
0..* Movimiento
mApellidos: String
mImporte: Real
mEdad: Integer mCuentaAsociada
mMovs mConcepto: String
Sexo: Genero
mFecha: Date
1 mtitular
0..*
mMovs

Fecha
mtarjetas 0..* <<datatype>>
mDia: Integer
Tarjeta mMes: Integer
MNombreTitular: String mAño: Integer
ObtenerMes(d: Date) : Integer

En toda cuenta debe haber al menos un titular de 18 años o más.

context Cuenta

inv: self.mTitulares->exists(c : Cliente | c.mEdad>=18)


47

Ejemplo de la op. exists (cont.)


<<enumeration>>
Genero
mCuentas Masculino
Cuenta femenino
0..*
mTitulares /msaldo: Real
! Cliente
1..*

mNombre: String mCuentaNómina


0..* Movimiento
mApellidos: String
mImporte: Real
mEdad: Integer mCuentaAsociada
mMovs mConcepto: String
Sexo: Genero
mFecha: Fecha
1 mtitular
0..*
mMovs

Fecha
mtarjetas 0..* <<datatype>>
mDia: Integer
Tarjeta mMes: Integer
MNombreTitular: String mAño: Integer
ObtenerMes(d: Fecha) : Integer

En toda cuenta debe haber al menos un titular de 18 años o más.

context
! Cuenta

inv: self.mTitulares->exists(mEdad>=18)
48
Operación Size

!  La operación predefinida size() nos permite obtener la cantidad de elementos


de una colección.

context Cliente

inv: self.mCuentas->size() < 10

mCuentas
Cuenta
0..*
mTitulares /msaldo: Real
1..*
Cliente
mNombre: String
mApellidos: String
mEdad: Integer
Sexo: Genero

49

Size and exists

context Habitación inv:

self.huespedes ->size() <= numero_de_camas


or

( huespedes->size() = numero_de_camas + 1 and

huespedes->exists(h: Huesped | h.edad <= 4) )

50
Otras operaciones
!  notEmpty()
" En el caso de una asociación con multiplicidad 0..1 es útil verificar si existe un objeto
o no cuando navegamos la asociación,

context Persona

inv: self.esposa->notEmpty() implies self.esposa.genero = Genero::femenino

<<enumeration>>

!  Union( colección_de_objetos )

!  Including( Objeto)

!  Intersection( colección_de_objetos ), sum()


51

Ejemplo de la op. collect


<<enumeration>>
Genero
mCuentas Masculino
Cuenta femenino
0..*
mTitulares /msaldo: Real
1..*
! Cliente
mCuentaNómina
mNombre: String
0..* Movimiento
mApellidos: String
mImporte: Real
mEdad: Integer mCuentaAsociada
mMovs mConcepto: String
Sexo: Genero
mFecha: Fecha
1 mtitular
0..*
mMovs

Fecha
mtarjetas 0..* <<datatype>>
mDia: Integer
Tarjeta mMes: Integer
MNombreTitular: String mAño: Integer
ObtenerMes(d: Fecha) : Integer

El saldo de toda cuenta debe ser siempre mayor o igual a cero (el
saldo se calcula como la suma del importe de sus movimientos).

context Cuenta inv:

52 self.mMovs->collect(mImporte)->sum() > 0
Ejemplo de la op. collect
<<enumeration>>
Genero
mCuentas Masculino
Cuenta femenino
0..*
mTitulares /msaldo: Real
1..*
! Cliente
mCuentaNómina
mNombre: String
0..* Movimiento
mApellidos: String
mImporte: Real
mEdad: Integer mCuentaAsociada
mMovs mConcepto: String
Sexo: Genero
mFecha: Fecha
1 mtitular
0..*
mMovs

Fecha
mtarjetas 0..* <<datatype>>
mDia: Integer
Tarjeta mMes: Integer
MNombreTitular: String mAño: Integer
ObtenerMes(d: Fecha) : Integer

El saldo de toda cuenta debe ser siempre mayor o igual a cero (el
saldo se calcula como la suma del importe de sus movimientos).

context Cuenta inv:

self.mMovs.mImporte->sum()
53 >0

Let y expresiones
<<definition>>
Expresiones let

!  A veces una subexpresión es utilizada mas de una vez en una


restricción. La expresión let nos permite definir una variable la cual
puede ser utilizada en una restricción.
context Persona

inv: let sueldo : Integer = self.job.salario->sum() in

If esDesocupado then

sueldo < 100 else

sueldo >= 100

55

Expresiones def
<<enumeration>>
Genero
mCuentas Masculino
Cuenta femenino
! mTitulares
0..*
/msaldo: Real
1..*
! Cliente
mCuentaNómina
mNombre: String
0..* Movimiento
mApellidos: String
mImporte: Real
mEdad: Integer mCuentaAsociada
mMovs mConcepto: String
Sexo: Genero
mFecha: Fecha
1 mtitular
0..*
mMovs

Fecha
mtarjetas 0..* <<datatype>>
mDia: Integer
Tarjeta mMes: Integer
MNombreTitular: String mAño: Integer
ObtenerMes(d: Fecha) : Integer

context Cuenta

def: saldo : real = self.mMovs.mImporte->sum()

context Cuenta
56
inv: saldo > 0
Reglas de
Derivación

Ejemplo de reglas de derivación


<<enumeration>>
Genero
mCuentas Masculino
Cuenta femenino
0..*
mTitulares /msaldo: Real
! Cliente
1..*

mNombre: String mCuentaNómina


0..* Movimiento
mApellidos: String
mImporte: Real
mEdad: Integer mCuentaAsociada
mMovs mConcepto: String
Sexo: Genero
mFecha: Fecha
1 mtitular
0..*
mMovs

Fecha
mtarjetas 0..* <<datatype>>
mDia: Integer
Tarjeta mMes: Integer
MNombreTitular: String mAño: Integer
ObtenerMes(d: Fecha) : Integer

context Cuenta:: msaldo

derive: msaldo : real = self.mMovs.mImporte->sum()

58
Ej. de reglas de derivación (cont.)
<<enumeration>>
Genero
mCuentas Masculino
Cuenta femenino
0..*
mTitulares /msaldo: Real
1..*
! Cliente
mCuentaNómina
mNombre: String
0..* Movimiento
mApellidos: String
mImporte: Real
mEdad: Integer mCuentaAsociada
mMovs mConcepto: String
Sexo: Genero
mFecha: Fecha
1 mtitular
0..*
mMovs

Fecha
mtarjetas 0..* <<datatype>>
mDia: Integer
Tarjeta mMes: Integer
/MNombreTitular: String mAño: Integer
ObtenerMes(d: Fecha) : Integer

El nombre del titular que figura en toda tarjeta es la concatenación del


nombre y apellidos del titular.

context Tarjeta

derive: self.mNombreTitular=
59
mTitular.mNombre.concat(“ “).concat(mTitular.mApellidos)

includes
<<enumeration>>
Genero
mCuentas Masculino
Cuenta femenino
0..*
mTitulares /msaldo: Real
1..* 1
! Cliente
mCuentaNómina
mNombre: String
0..* Movimiento
mApellidos: String
mImporte: Real
mEdad: Integer mCuentaAsociada
mMovs mConcepto: String
Sexo: Genero
mFecha: Fecha
1 mtitular
0..*
mMovs

Fecha
mtarjetas 0..* <<datatype>>
mDia: Integer
Tarjeta mMes: Integer
MNombreTitular: String mAño: Integer
ObtenerMes(d: Fecha) : Integer

Representamos la restricción de subconjunto de UML

context Cliente inv:

self.mCuentas->includes(self.mCuentaNómina)
60
includesAll
<<enumeration>>
Genero
mCuentas Masculino
Cuenta femenino
0..*
mTitulares /msaldo: Real
1..* *
! Cliente
mCuentaNómina
mNombre: String
0..* Movimiento
mApellidos: String
mImporte: Real
mEdad: Integer mCuentaAsociada
mMovs mConcepto: String
Sexo: Genero
mFecha: Fecha
1 mtitular
0..*
mMovs

Fecha
mtarjetas 0..* <<datatype>>
mDia: Integer
Tarjeta mMes: Integer
MNombreTitular: String mAño: Integer
ObtenerMes(d: Fecha) : Integer

Supongamos que el nombre de rol mCuentaNomina tiene cardinalidad *

context Cliente inv:

self.mCuentas->includesAll(self.mCuentaNómina)
61

Diagramas de Estados
<<enumeration>>
Genero
mCuentas Masculino
Cuenta femenino
0..*
mTitulares /msaldo: Real
1..* *
Cliente
! mNombre: String mCuentaNómina
Movimiento
mApellidos: String 0..*
mImporte: Real
mEdad: Integer mCuentaAsociada
mMovs mConcepto: String
Sexo: Genero
mFecha: Fecha
1 mtitular
0..*
mMovs

Fecha
mtarjetas 0..* <<datatype>>
mDia: Integer
Tarjeta mMes: Integer
MNombreTitular: String mAño: Integer
ObtenerMes(d: Fecha) : Integer

Supongamos que Cuenta tiene tres estados: SaldoCero, Bloqueda, y


SaldoPositivo

context Cuenta

inv: self.oclInState(SaldoCero) implies (msaldo = 0 or mMovs->isEmpty() )

62
inv: self.oclInState(SaldoPositivo) implies (msaldo > 0)
Ejercicio ¿?

context Componente inv:

self.utiliza-> forAll (s | self.desarrolladores.conoce->asSet()-> includes(s) )

63

Ejercicio ¿?

context Libro inv:

self.autores ->forAll (a | self.ediciones->exists (e | e.pais = a.pais) )

64
Expresiones OCL init

Movimiento
mImporte: Real
context Tarjeta::mMovs mConcepto: String
mFecha: Fecha
!
init: Set{} 0..*
mMovs

Cliente
mNombre: String
mApellidos: String
mEdad: Integer
Sexo: Genero

1 mtitular

0..*
mtarjetas

Tarjeta
/mNombreTitular: String
mValidoDesde: Fecha
mValidoHasta: Fecha

65

Includes, if, implies


context Servicio::utiliza(h : Huesped)

pre:

if habitación->notEmpty() then

habitacion.huespedes->includes(h)

else

h.habitacion.numero_piso =

self.piso_numero

endif

post: usos = usos@pre +1

66
Práctica
sobre OCL

indice

!  Vamos a mencionar primero algunos


puntos a tener en cuenta en la ejercitación.

!  Luego vamos a ver un ejercicio similar a los


que desarrollarán Uds.

68
A tener en cuenta...

Es importante tener en cuenta...

!  No escriban su nombre y apellido en los ejercicios.


!  Sean sinceros al escribir sus respuestas

!  La cantidad de Ejercicios: Hay 4 ejercicios que deben realizar. Cada uno


corresponde a un modelo UML/OCL

!  El orden en la ejercitación: Se requiere hacer los ejercicios en el orden en


el cual estos son entregados.

!  La secuencialidad de los ejercicios: Una vez finalizado un ejercicio es


posible comenzar un nuevo ejercicio. No es posible comenzar un
ejercicio y luego volver a un ejercicio anterior!.

69

A tener en cuenta...
Es importante tener en cuenta...

!  Ser precisos en la especificación del tiempo: En el desarrollo del


ejercicio se les solicita apuntar el momento (expresado en Hs. Min. y
Seg) en el cual se inicia un ejercicio, y una vez terminado una parte del
mismo se solicita apuntar nuevamente el tiempo de finalización. No
olviden escribir el tiempo!!.

!  La duración de tiempo en cada ejercicio: No importa si tardan más o


menos tiempo en el desarrollo del ejercicio, uds. tarden el tiempo que les
insume resolver el ejercicio.

!  Pero, cuando necesiten descanzar, o tomarse un tiempo, que sea luego


de haber finalizado una parte de un ejercicio.
"  El tiempo es una variable que es útil para nuestros estudios.

"  Publicaremos los resultados de los ejercicios en la pagina web de la materia.

70
Ejemplo de ejercicio
Indique el horario en el cual inicia el ejercicio: Hora:..........Min:.........Seg:..........
context Auto inv:

self.mantenimientos->select(m|m.repuestos->notEmpty() )

->forAll(e| e.tipo = self.pertenece.tipo)

71

Preguntas sobre expresiones


1. ¿A cuántas clases (distintas) se ha navegado a partir de la expresión? Indique el
número y el nombre de esas clases a las cuales se ha navegado:

Rta: se navego hacia 3 clases, Mantenimiento, Repuestos, Grupo_Autos.

2. Alguna parte de la expresión OCL enunciada anteriormente significa alguna de las


siguientes expresiones escritas en Lenguaje Natural. ¿Cuál de las siguientes
opciones es verdadera?

• - Todos los mantenimientos de un auto, tienen un tipo de


mantenimiento que es igual al tipo de grupo al que pertenece el auto.

• - Todos los mantenimientos de un auto, que han utilizado repuestos,


V tienen un tipo de mantenimiento que es igual al tipo de grupo al que
pertenece el auto.

• - Todos los mantenimientos de un auto, que no han utilizado


repuestos, tienen un tipo de mantenimiento que es igual al tipo de
grupo al que pertenece el auto.
Indique el horario en el cual finaliza el ejercicio: Hora:..........Min:.........Seg:..........
72
Parte II Modificaciones

Indique el horario en el cual inicia el ejercicio: Hora:..........Min:.........Seg:..........


5. Se requiere rescribir la expresión OCL de tal forma que sean válidos los siguientes requerimientos:

Se requiere rescribir la expresión OCL de tal forma que sea válido el siguiente
requerimento:

- Todos los mantenimientos de un auto, que no utilizan repuestos, tienen un


tipo de mantenimiento que es menor al doble del nivel del grupo al que pertenece
el auto.

context Auto inv:

self.mantenimientos->select(m|m.repuestos->Empty() )

->forAll(e| e.tipo < (2 * self.pertenece.tipo) )

Indique el horario en el cual finaliza el ejercicio: Hora:..........Min:.........Seg:..........

73

Implementando OCL en Java


Los modelos UML/OCL especifican como el sistema debería
estar estructurado y que debería hacer el sistema pero no
como debería ser implementado.
!
Para mostrar como construir código desde expresiones
OCL, en primer instancia debemos implementar los
elementos del modelo definidos en un diagrama.

La implementación de expresiones OCL que hacen


referencia a cualquier propiedad debe ser coherente con el
acceso a tales propiedades.

Además, como regla del proceso de transformación los


fragmentos de código de las expresiones OCL deben ser
utilizadas de acuerdo a sus roles en el modelo (invariante,
definición de atributo, derivación de regla, etc). Los
fragmentos de código deben estar ubicados en la
implementación de tal forma que ellos alcancen su
propósito.
74
Implementando OCL con una
tecnología relacional

Deberiamos derivar estructura de los diagramas de clases


en un conjunto de tablas, y definición de dominios
!
Representar las expresiones OCL como cláusulas check
basadas en atributos, cláusulas check por tuplas,
afirmaciones (assertions), etc.

75

Implementando OCL

El
! orden de los pasos durante el proceso de implementación es el
siguiente:

(p1) Definir la implementación de los elementos del modelo UML

(p2) Definir la implementación de la librería estándar OCL

(p3) Definir la implementación de las expresiones OCL

(p4) Ubicar correctamente los fragmentos de código que


implementan las expresiones OCL en el código de los
elementos del modelo.
76
(p1) la
implementacion de los
elementos del modelo
UML/OCL

(p1) clases

p.1.1. clases se transforman en clases Java


Tarjeta
! /mNombreTitular: String
mValidoDesde: Fecha
mValidoHasta: Fecha

public class Tarjeta { ....}

78
(p1) atributos
p.1.2. Cada atributos (privado, protegido, publico) de una
clase se transforma en un miembro de clase, privado, con
operaciones get y set en la clase Java. La visibilidad de las
! operaciones es equivalente a la visibilidad del atributo.
Si el atributo es read-only, la operación set se omite.

AttributeType getAttributeName()

void setAttributeName (AttributeType newValue) Tarjeta


/mNombreTitular: String
mValidoDesde: Fecha
mValidoHasta: Fecha

public class Tarjeta { Fecha


<<datatype>>

Fecha mValidoDesde mDia: Integer


mMes: Integer
mAño: Integer
obtenerMes(d: Fecha) : Integer
public void setValidoDesde(Fecha f) {mValidoDesde = f;}; estaAntes(d: Fecha): Boolean

public Fecha getValidoDesde() {return mValidoDesde};

79

(p1) asociaciones
p.1.3. Cada Extremo de asociacion en el modelo se Movimiento
mImporte: Real
transforma en un miembro de clase, privado, con mConcepto: String
mFecha: Fecha
operaciones get y set en la clase Java. La visibilidad
! de las operaciones es equivalente a la visibilidad 0..*
mMovs
del extremo en el modelo.

Si la multiplicidad es mayor a uno, el tipo del


miembro de clase es la implementación Java de Set
Cliente
mNombre: String
o de OrderedSet, dependiendo si la asociación esta
mApellidos: String
mEdad: Integer
etiquetada con {ordered} o no. Sexo: Genero

1 mtitular
public class Tarjeta {

Cliente titular; 0..*


mtarjetas

HashSet mMovs = new HashSet() ; Tarjeta


/mNombreTitular: String
mValidoDesde: Fecha
context Tarjeta::mMovs mValidoHasta: Fecha

init: Set{}
80
(p1) asociaciones cont.
public class Tarjeta { Movimiento
mImporte: Real
mConcepto: String
Cliente titular; mFecha: Fecha

!
HashSet mMovs; 0..*
mMovs

public void setTitular(Titular t) {

titular = t; } Cliente
mNombre: String
mApellidos: String
public Titular getTitular(Titular t) { mEdad: Integer
Sexo: Genero

return titular; }
1 mtitular

public void agregarMovimiento(Movimiento m) { 0..*


mtarjetas

mMovs.add(m); } Tarjeta
/mNombreTitular: String
mValidoDesde: Fecha
Public HashSet getmMovs() { mValidoHasta: Fecha

return mMovs}
81

(p1) otros elementos del


modelo

p.1.4. Cada tipo enumerado en el modelo se Tarjeta


/mNombreTitular: String
transforma en una clase Java, conteniendo mValidoDesde: Fecha
miembros de clase publica, estáticos, para cada mValidoHasta: Fecha
! literal de la enumeración.
Fecha
<<datatype>>
p.1.5. Cada interfaz del modelo se transforma en una mDia: Integer
mMes: Integer
interfaz Java mAño: Integer
obtenerMes(d: Fecha) : Integer
estaAntes(d: Fecha): Boolean
p.1.6. Cada estado de un diagrama de estado para una
clase se transforma en un miembro de clase de
tipo booleano. Se agregan restricciones para
verificar que la clase esta en un solo estado.

82
(p2) la
implementacion de una
libreria estandard de
OCL

(p2) Implem. una librería standard

Mapeo de tipos básicos de OCL a Java.


!
OCL type Java Type

Integer int

Real real

String String

Boolean boolean

84
(p2) Implem. una librería standard

Mapeo de tipos colección de OCL a Java.

OCL
! collection Type Java Type

Set HashSet

Sequence, Bag, OrderedSet ArrayList

Existen dos tipos de operación de colección aquellas que iteran sobre cada
elemento de la colección para realizar una operación (exists, select, collect) y otras
que son mas simples como union, size.
A las primeras se las denomina iteradores de colección. No existen operaciones
equivalentes en Java para todas las operaciones de colección de OCL !

85

(p2) Implem. una librería standard


Movimiento
mImporte: Real
Por ejemplo dada la siguiente expresión donde mMovs es un set mConcepto: String
mFecha: Fecha

mMovs->select(importe > 100)


! 0..*
mMovs

esta puede ser transformada en el siguiente código Java:

Iterator it = mMovs.iterator();

Set result = new HashSet();

While (it.hasNext()) {

Movimiento elem = ( Movimiento ) it.next() ;


Tarjeta

if ( elem.importe > 100 ) { /mNombreTitular: String


mValidoDesde: Fecha
mValidoHasta: Fecha

result.add(elem) ;
86
}} return result;
(p3) la
implementación de las
expresiones OCL

(p3) accediendo a propiedades

El acceso a propiedades (atributos ó extremos de asociación)


depende del mapeo de la propiedad UML a Java.
!

self.attribute

es transformado a

this.getAttribute();

self.associationEnd # navegacion

es transformado a

this.getAssociationEnd(); # operationCall

88
(p3) orden de evaluacion!

self.titular.tipo >= 0 or self.titular->isEmpty()

!
(this.getTitular().getTipo() >= 0 )

||
Cliente
mNombre: String
(this.getTitular() == null) mApellidos: String
mEdad: Integer
tipo: Integer

0...1 mtitular

Error de java.lang.nullPointerException
0..*

por hacer referencia a un objeto que no existe


mtarjetas

Tarjeta
/mNombreTitular: String
mValidoDesde: Fecha
mValidoHasta: Fecha

89

(p3) reglas de derivación


context Tarjeta::mNombreTitular
Cliente
mNombre: String
derive: self.mNombreTitular= mApellidos: String
mEdad: Integer
! Sexo: Genero
mTitular.mNombre.concat(“ “).concat(mTitular.mApellidos)
1 mtitular

Opción A. Implementar una operación...

string getNombreImpreso() { mtarjetas 0..*

Tarjeta
return getTitular().getNombre() /mNombreTitular: String
mValidoDesde: Fecha
mValidoHasta: Fecha
+ “ “ + getTitular.getApellidos(); }

Opcion B. Implementar un atributo, sin embargo necesitamos


un observer. Los objetos en los cuales depende la regla de
derivación deben notificar a este atributo cuando se
modifiquen

En ambos casos nunca tienen una operación pública set.


90
(p4) Ubicando los fragmentos de
codigo de las expresiones en la
implementacion de los elementos del
modelo

(p4) expr. invariantes

Escribimos una operación con resultado booleano.

! Y luego incluimos otra operación que llame a todas


operaciones que implementan invariantes.

context Tarjeta Tarjeta


MNombreTitular: String
inv fechasValidas: mValidoDesde: Fecha
mValidoHasta: Fecha

self.mValidoDesde.estaAntes(mValidoHasta)

Implementar una operación... Fecha


<<datatype>>
mDia: Integer
boolean invfechasValidas() { mMes: Integer
mAño: Integer
obtenerMes(d: Fecha) : Integer

return mValidoDesde.estaAntes(mValidoHasta) } estaAntes(d:Fecha): Boolean

92
(p4) expr. invariantes

2. Expresiones Invariantes.

! context Tarjeta
inv: titular.mEdad > = 18

Implementar una operación...


Cliente
mNombre: String
boolean invEdadCorrecta() { mApellidos: String
mEdad: Integer
Sexo: Genero
return getTitular().getmEdad() >= 18; } 1 mtitular

boolean chequearTodosLosInv () {
mtarjetas 0..*

Tarjeta
MNombreTitular: String
return invfechasValidas() & mValidoDesde: Fecha
mValidoHasta: Fecha

invEdadCorrecta() && .... }


93

(p4) pre y postcondiciones

context Cliente::agregarTarjeta ( t : Tarjeta)

! pre: not mtarjetas->includes(t)


post: mtarjetas = mtarjetas@pre ->including(t)
Cliente
mNombre: String
mApellidos: String

Void agregarTarjeta(Tarjeta t) { mEdad: Integer


Sexo: Genero

agregarTarjeta(t: Tarjeta)
assert( ! mtarjetas.contains(t) ) ; 1 mtitular

tarjetas_old = new ArrayList(mtarjetas);

// ... mtarjetas 0..*

Tarjeta
// <cuerpo de la operacion> MNombreTitular: String
mValidoDesde: Fecha
mValidoHasta: Fecha

//
94
assert (mtarjetas = tarjetas_old.add(t) ); }
Otras transparencias no
utilizadas en el curso

Propiedades: Operaciones

Que sucede si la operación tiene parámetros?

!  OCL tiene en cuenta si los parametros de una operación son par. de


entrada (in), de salida (out) o de entrada/salida (in/out).

!  Por ejemplo:

aDocente.ingreso(aFecha)

!  Si la operación no tiene parametros de salida o entrada/ salida, el


resultado del llamado a la operación es el valor del tipo de retorno de la
operación.

96
Propiedades: Operaciones

!  Si la operación tiene parámetros de salida o entrada/salida, el


resultado de esta operación es una tupla consistiendo de los
parámetros de salida, entrada/Salida y resultado.
context Docente::ingreso (d: Date, ticket: Integer) : Integer
post: result = Tuple {ticket = ..... , result = ........}

param. de
entrada param. de
salida

97

Propiedades: Operaciones

Cuando la operación no tiene parámetros de salida o entrada/salida el tipo


de result, es el tipo de retorno de la operación.

context Docente::ingresoA(d:Fecha) : Integer

post: result = age * 10000

Cuando una operación tiene parámetros de salida o entrada/salida,


el tipo retornado es una tupla.

context Docente::ingreso (d: Fecha, ticket: Integer) : Integer


post: result = Tuple {ticket = ..... , result = ........}

98
Propiedades: Operaciones
param. de
entrada param. de
salida

Ejemplo: la operación ingreso podría tener un parámetro de salida ticket, y el


resultado de la invocación a la operación es de tipo Tupla(ticket: Integer, result:
Integer). Ej de acceso a los parámetros:

aDocente.ingreso(aFecha).ticket = 300 and

aDocente.ingreso(aFecha).result = 500

Note que los parámetros de salida no necesitan incluirse en el llamado a la


operación, mientras que los parámetros de entrada o entrada/Salida sí.

99

Operación
  iterate
Collection->iterate(

element: Type 1 ;
! acum : Type2 = <expresion>

| <expression-con-element-y-acum> )

El valor resultante es acumulado en la variable ‘acum’. El acumulador


obtiene un valor inicial.

Para cada elemento de la colección fuente, la expresion del cuerpo es


calculada usando el valor previo de la variable ‘acum’.

Set{1,2,3}-> iterate( i: Integer, sum: Integer = 0 | sum + i)


10
0
Ejemplo 7
 

context Cuenta inv: Cuenta


/msaldo: Real

! let r: Integer = self.mTitulares mCuentas


0..*

->Iterate(

p: Titular ;
1..*
mTitulares
Cliente
mNombre: String
mayores: Integer = 0 | mApellidos: String
mEdad: Integer
Sexo: Genero
if p.mEdad >= 18 then

mayores +1

else mayores

endif )

in
10r > 0
1

Guía práctica 2. La
vista lógica
Introducción
!  En la Vista Lógica se definen los modelos
que representan el diseño detallado
!  Se definen las capas de la aplicación y los
componentes principales dentro de cada
capa
!  Se crean mecanismos comunes para
establecer las funcionalidades a las
diferentes áreas de la aplicación

Acciones de la Vista Lógica


!  En esta vista se deciden los siguientes puntos:
"  Como se establecen las pantallas de interfaz a partir
de la funcionalidad de los casos de uso
"  Como se encapsula la funcionalidad de las clases de
dominio en los componentes de la lógica de negocio
"  Como se definen las clases que realizan el mapeo
objeto-relacional
"  Como las clases del modelo orientado a objetos se
transforman en tablas de la base de datos
Necesidad de la Arquitectura del Software
!  Para pasar del análisis del sistema al diseño es
necesario tomar previamente decisiones sobre
la arquitectura del software va a tener nuestra
aplicación
!  La arquitectura establece:
"  División en capas de nuestro sistema en función de
sus necesidades de distribución
"  Una configuración de los componentes que nos
proporciona una vista a grandes rasgos de la
estructura de nuestra aplicación y como se va a
ubicar la funcionalidad

Arquitectura de Capas
! Patrón de arquitectura [Buschmann] que
establece la distribución de una aplicación en
divisiones lógicas desarrolladas y mantenidas
como módulos independientes, incluso en
plataformas distintas
!  La arquitectura de 3 capas esta divida en:
"  Interfaz de usuario, componentes que interactúan
con el usuario final
"  Lógica de negocio, contienen las reglas de negocio
de nuestra aplicación
"  Persistencia, contiene el acceso y almacenamiento
de los datos.
Refinamiento del Modelo de Capas
Modelo Cliente/Servidor Modelo 3 Capas Modelo 6 Capas (Refinado )

Interfaz de Usuario Interfaz de Usuario Presentación


o Presentación o Presentación

Control de Usuario

Control de
Procesos deprocesos
Negocio
Lógica de Negocio
Objetos dede
Entidades Negocio
Negocio

Servidor

Acceso a Datos
Persistencia
F Datos
ísica de
Físicos
Datos

Refinamiento del Modelo de Capas


!  Interfaz de Usuario: Capa encargada de dotar de la
funcionalidad necesaria para la interacción entre el
usuario y la aplicación. Dicha capa contiene tanto la
funcionalidad de la presentación del contenido, como la
interacción o control de la interfaz de usuario. Esta capa,
se divide en 2 subcapas:
"  Presentación: Contiene únicamente la funcionalidad de aspecto
o presentación, y recibe las peticiones del usuario que en
algunos casos serán validadas. En una aplicación Web
correspondería a la interfaz ofrecida por las páginas HTML,
javascript, CSS.
"  Control de Usuario: Capa que se encarga de recibir las
peticiones del usuario, gestionando la navegación de la interfaz
de usuario, y redireccionando las peticiones a la lógica de
negocio, la cual procesará la petición y devolverá un resultado al
control de usuario. A nivel de implementación, correspondería a
un Servlet, JSP, ASP.NET, etc.
Refinamiento del Modelo de Capas
!  Lógica de Negocio: Esta es la parte del sistema que
resuelve las reglas de negocio especificadas para el
dominio del problema. Es lo que se domina en ingles
middleware . En dicha capa se puede encontrar en
multitud de configuraciones que pueden ser distribuidas
o no. Por otro lado, dicha capa puede separar su
funcionalidad en dos subcapas:
"  Procesamiento de Control: Esta parte del sistema se encarga de
atender las peticiones que se reciben del cliente, convirtiéndolas
en procesos que se realizará de forma transaccional o no, de
forma síncrona o asíncrona. Ejemplos de implementación son
los Session de EJB o CORBA, o los componentes COM de
Microsoft.
"  Entidades de Negocio: En esta capa residen los elementos que
contienen la representación de los objetos definidos en el
dominio del problema. Ejemplos de implementación son los
Entity de EJB o clases en .NET.

Refinamiento del Modelo de Capas


!  Persistencia: parte del sistema encargada de dotarle de
almacenamiento o persistencia a los datos de la
aplicación Web. Ejemplos de implementación de la
persistencia es cualquier base de datos y su mecanismo
de acceso. Se puede dividir su funcionalidad en 2
subcapas:
"  Acceso a Datos: Esta capa se encarga de contener aquellos
componentes que permiten el acceso a los datos físicos desde
la capa de lógica de negocio. P.e las clases que lanzan las
sentencias SQL a la base de datos.
"  Datos Físicos: representa las fuentes físicas de datos que va a
contener nuestro sistema. Un ejemplo de implementación sería
cualquier base de datos.
Arquitectura Posible de una Aplicación
Tipos de Componentes

Interfaz de Usuario
3 Capas Lógicas

Interfaz de Usuario Componentes de


Proceso de Negocio
Lógica de Negocio

Persistencia

Entidades de Componentes de
Negocio Acceso a Datos

Datos de la
Aplicación

Componentes de Interfaz de Usuario


!  Se encargan de procesar y dar formato a la
entrada de datos, adquirir y validar los datos
entrantes y navegar entre las diferentes
pantallas
!  Un único componente encapsula la
funcionalidad de presentación y control de
usuario
!  Los componentes de IU se pueden implementar
utilizando formularios standalone (p.e. Windows)
o Web, usando controles u otro tipo de
tecnología que permita capturar los datos de
entrada
Componentes de Proceso de Negocio
!  El Componente de Proceso de Negocio (CPN)
se encarga de exponer los métodos de más alto
nivel que la lógica de negocio expone al cliente
!  Permite independizar la funcionalidad ofertada
de como esté realizada la implementación de los
métodos invocados
!  Al reducir el interfaz entre las capas está
implementando el patrón Façade [Gamma et al.,
1995] reduciendo el acoplamiento entre el
interfaz de usuario y la lógica de negocio

Componente de Proceso de Negocio


!  Este componente contiene la lógica de negocio
que involucra a procesos complejos donde
intervienen más de una entidad de negocio. Por
ejemplo, la creación de una factura y sus líneas
a partir de un Pedido y sus líneas
!  Inicia y finaliza las transacciones de manera que
las Entidades de Negocio y Componentes de
Acceso a Datos estén dentro del contexto de
una transacción
!  Puede contener la autorización para el acceso a
determinada funcionalidad por parte del usuario
!  Su implementación debe ser distribuida EJB en
J2EE o COM en .NET
Entidades de Negocio (EN)
!  Componentes que representan entidades de
negocio del mundo real, p.e. un producto, un
pedido
!  Contienen normalmente la información de una
clase de dominio con sus atributos,
operaciones y restricciones. Aunque pueden
representar una composición de clases
!  Tienen asociado un Componente de Acceso a
Datos que le proporciona el acceso y el mapeo
objeto-relacional
!  Pueden ser representados de múltiples
maneras, p.e. clases personalizadas,
Estructuras de registros, XML, etc.

Componentes de Acceso a Datos


!  Los Componentes de Acceso a Datos (CADs)
encapsulan la tecnología de acceso a datos y la
BD al resto de la aplicación.

!  Proporciona un interfaz sencillo que permite


recuperar los datos de la BD y salvar una
entidad de negocio en la BD

!  Los CADs también contienen cualquier lógica de


negocio necesaria para alcanzar las
operaciones relacionadas con los datos
Arquitectura de Petstore
Componentes de
Interfaz de Usuario

Entidades de Componentes de
Negocio Acceso a Datos

Datos de la
Aplicación

En Petstore no son necesarios de los componentes de proceso de


negocio debido a que carece de lógica compleja más allá de las
operaciones CRUD

Paso de Análisis al Diseño


!  Definidos los modelos de la fase de análisis,
concretamente el modelo de casos de uso y el modelo
de dominio
!  Y suponemos definida la arquitectura de nuestra
aplicación (capas y componentes)
!  Procedemos al diseño detallado de nuestra aplicación:
"  Modelo de diseño de Interfaz de Usuario
"  Modelo de diseño de Logica de Negocio
"  Modelo de diseño de Persistencia
"  Diagrama Entidad-Relación
!  Primero mostraremos los modelos de Petstore reducidos
que permitirán una mayor comprensión del problema
Modelo de Casos de Uso de Petstore Reducido

<<extend>>

Si el cliente no
Validar Cliente está registrado Registrar Cliente

<<include>>

<<include>>

Realizar Pedido Pagar Pedido


Cliente
<<include>>

<<extend>>

Buscar Producto Si el cliente Anyadir Producto


decide comprarlo

<<extend>>

Consult ar Producto Por Categoria

Modelo de Dominio Reducido de Petstore


Pedido
pedidoId : String
Cliente fecha : Date
direccion : String
clienteId : String
localidad : String
nombre : String
provincia : String LineaPedido
NIF : String
1 0..n codigoPostal : Integer 1 0..n lineaPedidoID : String
email : String
tipoPago : String unidades : Integer
login : String
tipoTarjeta : String
password : String
numeroTarjeta : Long anyadirProducto()
fechaCaducidad : Date
validarCliente() 0..n
estado : String
registrarCliente()
realizarPedido()
pagarPedido()

1
Producto
Categoria productoId : String
categoriaId : String nombre : String
1 0..n
nombre : String descripcion : String
descripcion : String urlFoto : String
precio : Single
verProductos()
BuscarProducto()
Interfaz de Usuario del Modelo de Diseño
!  A partir de los casos de Uso debemos determinar que
componentes de interfaz de usuario se han de
representar
!  Definimos una clase pantalla genérica que contendrá
toda la funcionalidad y controles necesarios para
representar un formulario en una pantalla
!  Cada una de las pantallas extenderá de dicha clase y le
incorporará la/s operacion/es que pueden invocarse
desde ella
!  La relaciones que existen entre las pantallas es de uso
puesto que unas se invocan a otras

Modelo de Diseño de Petstore


Paquete Interfaz Usuario
Pantalla
paneles : java.util.Vector
botones : java.util.Vector
textos : java.util.Vector
etiquetas : java.util.Vector
Pantalla Registrar Cliente Pantalla Categoria
Pantalla()
registrarCliente()
desplegarPantalla() verProductos()
inicializarPantalla()
borrarPantalla()
<<uses>>
agregarBotonesSalir()
agregarBotonesServiciosSalir()
crearPantalla()
<<uses>>
Pantalla Producto
BuscarProducto()
<<uses>>
Pantalla Validar Cliente
validarCliente()
<<uses>> <<uses>>

Pantalla Realizar Pedido <<uses>>


<<uses>> Pantalla Anyadir Producto
realizarPedido()
<<uses>> anyadirProducto()
pagarPedido()
<<uses>>

Sesion
<<uses>>
insertarObjeto()
obtenerObjeto()
duracionSesion() Si estamos en Web la sesion es mantenida por el propio motor.
Si estamos en Windows, la sesión estaría referenciada por una pantalla
principal que estaría en ejecución en todo momento
Entidad de Negocio (EN)
!  Un modelo de dominio contiene múltiples clases
con relaciones y debemos decidir como mapear
las clases en diferentes componentes EN

!  Cuando se define las EN se debe considerar


como se usará la información en la aplicación

!  Es mejor identificar el núcleo de EN que


encapsulan la funcionalidad de la aplicación,
antes que definir una EN por cada clase

Entidad de Negocio
!  Tómate tu tiempo para analizar y modelar las
EN de tu aplicación, en lugar de definir una EN
por cada clase

!  Básate en las composiciones y herencias UML


para componer objetos complejos

!  No definas EN separadas para representar


relaciones muchos-a-muchos. Estas relaciones
pueden ser implementadas a través de los
métodos de los EN implicados
Entidades de Negocio en Petstore
!  En el Modelo de Dominio de Petstore hay una
composición entre Pedido y Línea de Pedido
!  Así podemos definir cuatro EN lógicas
principales que controlen la aplicación:
"  Un Cliente
"  Un Pedido contendrá la entidad lógica de líneas de
pedido pero solo tendrá visibilidad la primera
"  Un Producto
"  Una Categoría

Modelo de Diseño de Petstore


Paquete Lógica de Negocio
Pantalla Realizar Pedido Pantalla Anyadir Producto
(from Interfaz Usuario) (from Interfaz Usuario)

Pantalla Validar Cliente realizarPedido() anyadirProducto()


Pantalla Registrar Cliente
(from Interfaz Usuario) (from Interfaz Usuario) pagarPedido()

registrarCliente() validarCliente() <<uses>> <<uses>>

<<uses>>
EN_Pedido Pantalla Producto Pantalla Categoria
<<uses>> pedidoId : String (from Interfaz Usuario) (from Interfaz Usuario)
fecha : Date
EN_Cliente direccion : String BuscarProducto() verProductos()
clienteId : String localidad : String
nombre : String provincia : String
Sesion NIF : String codigoPostal : Integer <<uses>>
(from Interfaz Usuario) email : String tipoTargeta : String <<uses>>
0..n 1 1 0..n
login : String tipoPago : String
insertarObjeto() password : String numeroTargeta : Long
obtenerObjeto() fechaCaducidad : Date EN_Producto
duracionSesion() validarCliente() estado : String productoId : String EN_Categoria
registrarCliente() nombre : String categoriaId : String
setAtributos() getAtributos() descripcion : String nombre : String
0..n 1
getAtributos() setAtributos() urlFoto : String descripcion : String
realizarPedido() precio : Single
La sesión referencia a un pagarPedido() getAtributos()
cliente que podrá realizar anyadirProducto() BuscarProducto() setAtributos()
más de un pedido. setAtributos() verProductos()
1
getAtributos()
0..n
EN_LineaPedido
lineaPedidoId : String
unidades : Integer

setAtributos()
getAtributos()
Componente de Acceso a Datos
!  Para cada EN, definimos un CAD que será definido
como sigue:
"  CAD_Cliente: Esta clase provee los servicios para recuperar y
modificar los datos de las tablas Cliente
"  CAD_Pedido: Esta clase provee los servicios para recuperar y
modificar los datos de las tablas Pedido y LineaPedido
"  CAD_Producto: Esta clase provee los servicios para recuperar y
modificar los datos de la tabla Producto
"  CAD_Categoria:Esta clase provee los servicios para recuperar y
modificar los datos de la tabla Categoria

Modelo de Diseño de Petstore


Paquete de Persistencia
EN_Cliente EN_Pedido EN_Categoria
EN_Producto (from LogicaNegocio Petstore)
(from LogicaNegocio Petstore) (from LogicaNegocio Petstore) (from LogicaNegocio Petstore)
clienteId : String pedidoId : String categoriaId : String
productoId : String
nombre : String fecha : Date nombre : String
nombre : String
NIF : String direccion : String descripcion : String
descripcion : String
email : String localidad : String urlFoto : String
login : String provincia : String getAtributos()
precio : Single
password : String codigoPostal : Integer setAtributos()
tipoTargeta : String verProductos()
BuscarProducto()
validarCliente() tipoPago : String setAtributos()
registrarCliente() numeroTargeta : Long getAtributos()
setAtributos() fechaCaducidad : Date 1
getAtributos() estado : String 1

getAtributos()
1 setAtributos()
realizarPedido()
pagarPedido()
anyadirProducto() 1
1 1
1
1
CAD_Cliente CAD_Pedido CAD_Producto CAD_Categoria

insertarCliente() insertarPedido() insertarProducto() insertarCategoria()


borrarCliente() borrarPedido() borrarProducto() borrarCategoria()
modificarCliente() modificarPedido() modificarProducto() modificarCategoria()
buscarCliente() buscarPedido() buscarProducto() buscarCategoria()
Recomendaciones
!  Definir todos los métodos que devuelven un tipo
concreto de Entidad de Negocio en un solo CAD
"  Por ejemplo, si se están recuperando todos los
pedidos de un determinado cliente, implementar la
función en PedidoCAD llamada
ObtenerPedidosPorCliente que devuelva los pedidos
filtrando por un idCliente

"  Contrariamente, si estás recuperando todos los


clientes que han pedido un específico producto,
implementa la función en ClienteCAD
ObtenerClientesPorProducto

Base de Datos de Petstore


Fase de Implementación
!  Una vez realizado el diseño de nuestra
aplicación, se procede a la implementación de
las clases propuestas
!  Existen múltiples implementaciones para un
mismo diseño, incluso dentro de una misma
plataforma
!  La plataforma seleccionada es .NET
concretamente mediante el lenguaje orientado a
objetos C#.
!  Se proponen una posible implementación
recomendada por Microsoft para su plataforma

Implementando el Componente
de Interfaz de Usuario en .NET
$  Para implementar el interfaz de usuario en .NET
se puede realizar en Windows Forms o Web Forms

$  El marco de trabajo en ambos casos permite


heredar de formularios existentes para añadir más
funcionalidades o modificar el comportamiento
existente

$  .NET permite programar ambos interfaces desde


su entorno visual programando únicamente los
eventos que invocan a la lógica de negocio
Windows Forms vs Web Forms
Característica Windows Forms Web Forms

Implantación Puede ejecutarse sin alterar el Registro No se requiere descarga

Los gráficos interactivos


Gráficos Incluye GDI+
o dinámicos requieren
ida y vuelta al servidor
para su actualización
Pueden aprovechar el
Velocidad de respuesta HTML Dinámico del
Respuesta más rápida posible para navegador y crear ricos
aplicaciones interactivas
IU
Requiere el .NET
Plataforma Framework ejecutándose Sólo requiere un
en la máquina cliente navegador

Basado en un modo de Los componentes de


Modelo de programación intercambio de mensajes aplicaciones se invocan
Win32 en el lado cliente mediante HTTP

Seguridad
Seguridad basada en Seguridad basada en
código y basada en roles roles

Cómo crear un formulario en Windows


Forms
$  Cuando se crea un nuevo
proyecto, se crea un
formulario base
$  Para crear un nuevo
formulario
1. Hacer clic con en botón derecho en el Explorador de
soluciones

2. Hacer clic en Agregar

3. Hacer clic en Windows Forms

Curso 08-09
Propiedades del formulario Windows Forms
Botón Eventos

Nombre Formulario

Botón Ordenación

Botón Alfabético

Panel Descripción

Curso 08-09

Propiedades del formulario Windows Forms (II)


!  Text
"  Texto que aparece en la franja superior del
formulario
!  Size
"  Tamaño del formulario
!  Name
"  Nombre del formulario
!  StartPosition
"  Posición donde debe aparecer el
formulario
Propiedades del formulario Windows Forms (III)
!  AcceptButton
"  Que botón se activa cuando su pulsa la tecla
Enter
!  CancelButton
"  Que botón se activa cuando su pulsa la tecla
Escape
!  AutoScroll
"  Si los scrollbars deben aparecer cuando se
llena más de una pantalla
!  FormBorderStyle
"  Borde del formulario (por ejemplo, ninguno,
sencillo, 3D)

Formularios Web Forms


$  Los formularios Web Forms están formados por
una combinación de HTML código y controles que
se ejecutan en un servidor Web ejecutando
Microsoft Internet Information Services (IIS)

$  Los formularios Web Forms muestran una interfaz


de usuario que genera HTML y que se envía al
navegador, mientras que el código de soporte y
los controles que la componen permanecen en el
servidor Web
Formularios Web Forms (II)
$  Esta división entre el interfaz en el cliente y el código en el
servidor es una importante diferencia entre los formularios
Web Forms y las páginas Web tradicionales

$  Mientras una página Web tradicional requiere que todo el


código se envíe y se procese en el navegador, los
formularios Web Forms únicamente necesitan enviar al
navegador los controles de la interfaz, y el proceso de las
páginas se mantiene en el servidor

$  Esta división entre IU y código aumenta el número de


navegadores soportados e incrementa la seguridad y
funcionalidad de la página Web.

Formularios Web Forms (III)


$  Extensión .aspx Los formularios Web Forms se
denominan habitualmente páginas ASP.NET o
páginas ASPX. Los formularios Web Forms tienen
una extensión .aspx y funcionan como
contenedores para el texto y los controles que
deseamos mostrar en el navegador

$  Las páginas ASP.NET (.aspx) y Active Server Pages


(ASP) (.asp) pueden coexistir en el mismo
servidor. La extensión del archivo determina si la
página la procesa ASP o ASP.NET
Formularios Web Forms (IV)

$  Los formularios Web Forms están


frecuentemente formados por dos archivos
distintos: el archivo .aspx contiene la IU
para el formulario Web Form, mientras que
el archivo .aspx.vb o .aspx.cs, denominado
página de código subyacente, contiene el
código de soporte

Atributos de un formulario Web


$  Las funciones de un formulario Web Form
están definidas por tres niveles de atributos

$  Los atributos de página definen las


funciones globales, los atributos de cuerpo
definen cómo se mostrará una página y los
atributos de formulario definen cómo se
procesarán los grupos de controles
Atributos de página
$  La etiqueta <@Page> define atributos específicos de la
página que utiliza el parseador de páginas ASP.NET y el
compilador
$  Únicamente podemos incluir una etiqueta <@ Page> por
archivo .aspx

<%@ Page Language="c#" Codebehind="WebForm1.aspx.cs"


SmartNavigation="true" %>

Atributos de página (II)


$  Language
$  El atributo Language define el lenguaje en el que está
escrito el script de la página Web. Algunos de los
valores de este atributo son: vb, c# y Jscript

$  Codebehind
$  El atributo de página Codebehind identifica la página
de código subyacente que tiene la lógica que soporta el
formulario Web Form. Cuando Visual Studio .NET crea
un formulario Web Form, como WebForm1.aspx,
también crea una página de código subyacente,
WebForm1.aspx.vb o WebForm1.aspx.cs
Atributos de cuerpo
$  Los atributos de la etiqueta <Body> definen el
aspecto de los objetos que se muestran en el
navegador del cliente

<body ms_positioning="GridLayout">

Atributos de cuerpo (II)


$  El atributo pageLayout (etiquetado como
ms_positioning) determina cómo se posicionan
los controles y el texto en la página
$  Existen dos opciones para pageLayout:
$  En FlowLayout, el texto, las imágenes y los controles
fluyen por la pantalla, dependiendo del ancho de la
ventana del navegador
$  En GridLayout, los campos de texto, las imágenes y
los controles de una página están fijados por
coordrnadas absolutas. Este es el valor por defecto
Atributos de formulario (II)
$  Los atributos de una etiqueta <Form> incluyen:
$  Method
$  El atributo Method identifica el método para enviar
valores de control de retorno al servidor. Las opciones
de este atributo son:
$  Post Los datos se pasan en pares nombre/valor dentro del

cuerpo de la petición HTTP (Hypertext Transfer Protocol)


$  Get Los datos se pasan en una cadena de consulta

Atributos de formulario (III)


$  Runat
$  Una de las principales características de un formulario
Web Form es que los controles se ejecutan en el
servidor
$  El atributo runat="server" hace que el formulario
publique información de control de retorno a la página
ASP.NET en el servidor donde se ejecuta el código de
soporte
$  Si el atributo runat no está establecido en "server", el
formulario funciona como un formulario HTML normal
Código por defecto
<%@ Page language="c#" Codebehind="WebForm1.aspx.cs"
AutoEventWireup="false" Inherits="WebApplication1.WebForm1" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<title>WebForm1</title>
<meta name="GENERATOR" Content="Microsoft Visual
Studio 7.1">
<meta name="CODE_LANGUAGE" Content="C#">
<meta name="vs_defaultClientScript"
content="JavaScript">
<meta name="vs_targetSchema"

Código por defecto (II)


content="http://schemas.microsoft.com/intellisense/ie5">
</head>
<body MS_POSITIONING="GridLayout">
<form id="Form1" method="post" runat="server">
'HTML y controles aquí
</form>
</body>
</html>
Implementación de Sesión
!  Una sesión es el período de tiempo en el que
un usuario particular interactúa con una
aplicación web.
!  Durante una sesión la identidad única de un
usuario se mantiene internamente.
!  Una sesión finaliza si hay un timeout o si tu
finalizas la sesión del visitante en el código.

¿Cuál es el uso de una sesión?


!  Las sesiones ayudan a preservar los datos entre
accesos sucesivos. Esto puede hacerse gracias
a los objetos de sesión

!  Los objetos de Sesión nos permiten preservar


las preferencias del usuario y otra información
del usuario al navegar por la aplicación Web
Ejemplo, uso de objetos de sesión
!  Imagina un sitio Web en el que se puede elegir el color
de fondo de las páginas a navegar. Necesitas recordar
la elección del usuario en cada página

!  Website de Petstore donde el cliente navega a través de


muchas páginas y quiere seguir conservando la
información de su persona y los artículos que ha ido
introduciendo en el pedido

Implementación de Sesión en
ASP.NET
!  Las sesiones son tablas Hash en memoria con un
timeout especificado.
Session[ username ] = Jose Martínez ;
Session[ color ] = Blue ;

!  Asignamos los valores a las variables de sesión


username y color , respectivamente. Si necesito
saber el username o color en páginas siguientes
puedo usar Session[ username ], Session[ color ].

!  Las sesiones en ASP.NET están identificadas usando


enteros 32-bit long conocidos como Session IDs. El
motor ASP genera estos session ID s de tal forma que
se garantice que son únicos
Implementando Componentes de Acceso a
Datos
!  Un CAD es una clase sin estado, es decir, todos
los mensajes intercambiados pueden ser
interpretados independientemente. Ningún
estado es guardado entre llamadas

!  Uno de los principales objetivos de un CAD es


encapsular o esconder la idiosincrasia de la
invocación y el formato de la BD a la aplicación
cliente

Operaciones de un CAD
!  Un CAD debería proveer los métodos para
realizar las siguientes tareas sobre la BD:
"  Crear registros en la BD
"  Leer registros en la BD y devolver las entidades de
negocio al componente invocante
"  Actualizar registros en la BD, usando entidades de
negocio proporcionadas por el componente invocante
"  Borrar registros de la BD

!  Estos métodos son llamados CRUD, acrónimo


de Create, Read, Update and Delete
Operaciones de un CAD (II)
!  Los CAD pueden contener también métodos que
realizan algún filtro. Por ejemplo, un CAD puede tener
un método para encontrar el producto más vendido en
un catalogo durante un mes

!  Un CAD accede a una única BD y encapsula las


operaciones relacionadas con una única tabla o un
grupo de tablas vinculadas de la BD.

!  Por ejemplo, podréis definir un CAD que controle las


tablas de Cliente y sus Direcciones, y otro CAD que
controle los Pedidos y las LineasDePedidos

Ejemplo de CAD en .NET


CAD para la clase Cliente
public class ClienteCAD
{
private string conn_string;
public ClienteCAD()
{
// Adquiere la cadena de conexión desde un único sitio
}
public ClienteDataSet GetCliente(string id)
{
// Código para recuperar un tipo DataSet conteniendo los datos del Cliente
}
public string CrearCliente(string nombre, string direccion, string ciudad, string pais, int codPostal)
{
Ejemplo de CAD (II)
// Código para crear un cliente basado en los parametros escalares
// Devuelve el ID del cliente en este método.
}
public void ActualizarCliente(ClienteDataSet clienteActualizado)
{
//Código para actualizar la BD, basado en el los datos del cliente enviados como un parámetro de tipo ClienteDataSet
}
public void BorrarCliente (string id)
{
// Código para borrar el cliente con el ID especificado
}
public DataSet ObtenerClientesPorCiudad (string nombre)
{
// Código para recuperar clientes usando un rol.
}
}

Método CAD: BorrarCliente


// Método para recuperar el Nombre del Cliente
public void BorrarCliente( string clienteID )
{
conn = null;
// Encapsula todo el acceso a datos dentro del try
string conexion = server=(local);Integrated
Security=SSPI;database=clientes
string comando = Delete from Cliente where id = + clienteID;
try
{
conn = new SqlConnection(conexion);
conn.Open();
SqlCommand cmd = new SqlCommand(comando, conn );
Método CAD: BorrarCliente (II)
cmd.ExecuteNonQuery();
}
catch (SqlException sqlex)
{
// Envuelve la excepción actual en una excepción mas relevante y la
reenvía
throw new CADException ( Error borrando el cliente: " + clienteID,
sqlex );
}
catch (Exception ex)
{
// Captura la condición general y la reenvía.
throw ex;
}
finally
{
if(conn != null) conn.Close(); // Se asegura de cerrar la conexión.
}}

Método CAD: ObtenerClientesPorCiudad


// Método para recuperar los clientes de una determinada ciudad
public void ObtenerClientesPorCiudad( string ciudad )
{
conn = null;
DataSet dsClientes = null;
// Encapsula todo el acceso a datos dentro del try
string conexion = server=(local);Integrated
Security=SSPI;database=clientes
string comando = Select * from Cliente where ciudad = + ciudad;
try
{
conn = new SqlConnection(conexion);
SqlDataAdapter sqlAdaptador = new SqlDataAdapter (comando, conn);
Método CAD: ObtenerClientesPorCiudad
dsClientes = new DataSet();
sqlAdaptador.Fill (dsClientes, cliente );
return dsClientes;
}
catch (SqlException sqlex)
{
throw new CADException ( Error en la consulta de clientes por ciudad: " + clienteID, sqlex );
}
catch (Exception ex)
{
// Captura la condición general y la reenvía.
throw ex;
}
finally
{
if(conn != null) conn.Close(); // Se asegura de cerrar la conexión.
}}

Otras tareas que puede realizar un CAD

!  Los CADs pueden realizar otras tareas en


su implementación:
"  Controlar la seguridad y autorización
"  Realizar la paginación de datos
"  Realizar la navegación por los datos si es
necesario
"  Implementar una estrategia de cache para las
consultas de datos no transaccionales
"  Invocar a procedimientos almacenados
Implementado Entidades de Negocio
!  Presentan las siguientes características:
"  Las EN proveen de un acceso con estado a los datos de
negocio e incorporan en otras ocasiones funcionalidad

"  Las EN son construidas desde los datos que proviene de una o
más tablas de la BD

"  Las entidades de negocio pueden ser pasadas como


parámetros de entrada/salida de procesos de negocio

"  Las EN pueden ser serializables, para hacer persistente el


estado actual de las entidades. P.e pueden ser guardadas en el
disco duro local, en una BD de escritorio si la aplicación trabaja
sin conexión, etc.

"  Las EN no inician transacciones, estas son iniciadas por la


aplicación cliente o por los procesos de negocio

Tipos de Representaciones de una EN


!  XML: Se usa una cadena XML o un objeto XML
DOM (Document Object Model). XML es un
formato abierto y flexible que puede ser usado
para integrar diversos tipos de aplicaciones
!  DataSet: representa una cache de las tablas de
una BD relacional
!  DataSet tipado: clase que hereda del DataSet
de ADO.NET que proporciona métodos
fuertemente tipados asociados a una tabla
concreta
Tipos de Representaciones de una EN
!  Componente Entidad de Negocio (CEN): clase
personalizada por cada entidad de negocio
(clase de dominio). Contiene los atributos y
propiedades para exponer la información a la
aplicación cliente. No contiene los métodos
CRUD para invocar a los CAD, sino que es el
cliente quien lo hace
!  CEN con CRUD: se define una clase
personalizada como la anterior, pero en este
caso es el CEN quien invoca directamente a los
métodos CRUD de CAD

Representado una EN con XML


!  El siguiente ejemplo muestra un producto
representado con XML
<?xml version="1.0"?>
<Producto xmlns="urn:aUniqueNamespace">
<IdProducto>1</IdProducto>
<Nombre>Caramelos de Menta </Nombre>
<Cantidad>10 cajas x 20 bolsas </Cantidad>
<PrecioUnitario>18.00</PrecioUnitario>
<UnidadesEnStock>39</UnidadesEnStock>
</Producto>
Representado en EN con XML
Permite representar objetos compuestos
<Pedido xmlns="urn:aUniqueNamespace">
<PedidoID>10248</PedidoID>
<ClienteID>VINET</ClienteID>
<Fecha>1996-07-04</Fecha>
<FechaEnvio>1996-07-16</FechaEnvio>
<LineasPedido>
<LineaPedido>
<ProductoID>11</ProductoID>
<PrecioUnitario>14.00</PrecioUnitario>
<Cantidad>12</Cantidad>
</LineaPedido>
<LineaPedido>
<ProductoID>42</ProductoID>
<PrecioUnitario>9.80</PrecioUnitario>
<Cantidad>10</Cantidad>
</LineaPedido>
</LineasPedido>
</Pedido>

Representado una EN con XML


!  Ventajas:
"  Utilización de un estándar de la W3C para la representación de
datos
"  Flexibilidad. XML permite representar jerarquías y colecciones
de información
"  Interoperabilidad. XML es una opción ideal para intercambiar
información con sistemas legados (externos), socios
comerciales, de forma independiente de plataforma.
!  Desventajas:
"  La correctitud del tipo no es preservada en XML
"  La validación de un XML es lenta
"  No permite el uso de campos privados
"  Requiere de un proceso complejo su ordenación
Representando una EN con Clases
!  Clases personalizadas que contienen los siguientes
miembros:
"  Atributos privados que cachean (o almacenan) los datos de la
entidad de negocio. Estos campos son una imagen de los datos
de la BD desde el momento que son recuperados por un CAD

"  Propiedades públicas para acceder al estado de la entidad y


acceder a composiciones y jerarquías de objetos

"  El nombre de las propiedades es independiente de los nombres


de la BD, se definen en función de la necesidad de la aplicación
(modelo de dominio)

"  Métodos y propiedades que realizan un procesamiento


localizado mediante el uso de los datos de la entidad

Representación de una CEN


public class ENProducto
get { return nombre; }
{
set { nombre = value; }
// Campos privados para mantener el
}
// estado de la Entidad Producto
public string CantidadPorUnidad
private int idProducto;
{
private string nombre;
get { return cantidadPorUnidad; }
private string cantidadPorUnidad;
set { cantidadPorUnidad = value; }
private decimal precioUnitario;
}
private int unidadesStock;
public decimal PrecioUnitario
private int stockMinimo;
{
// Propiedades publicas para exponer el
get { return precioUnitario; }
// estado del producto
set { precioUnitario = value; }
public int IdProducto
}
{

get { return idProducto; }
set { idProducto = value; }
}
public string Nombre
{
Representación de una CEN (II)
// Métodos que realizan algún procesamiento
public void IncrementarPrecioUnidadPor (decimal
cantidad)
{
precioUnitario += cantidad;
}

public short UnidadesSobreElNivelMinimo


{
get { return (short)(unidadesStock -
stockMinimo); }
}
}//Fin de Clase

Composición en un CEN
Ejemplo de Pedido y sus Líneas de Pedido en .NET
public class ENPedido public string IdCliente
{ {
// Atributos de Pedido get { return idCliente; }
private int idPedido; set { idCliente = value; }
private string idCliente; }
private DateTime fechaPedido; public DateTime FechaPedido
private DateTime fechaEnvio; {
// Atributo que contiene las Lineas de Pedido get { return fechaPedido; }
private DataSet lineasPedido; set { fechaPedido = value;}
// Propiedades públicas }
public int IdPedido public DateTime FechaEnvio
{ {
get { return idPedido; } get { return fechaEnvio; }
set { idPedido = value; } set { fechaEnvio = value; }
} }
Composición en un CEN
// Propiedad para exponer públicamente las Líneas de Pedido
public DataSet LineasPedido
{
get { return lineasPedido; }
set { lineasPedido = value; }
}
// Métodos adicionales para simplificar el acceso a las Lineas
public bool estaProductoEnPedido (int idProducto)
{
// La clave primaria debe estar definida en la DataTable
DataRow fila = lineasPedido.Tables[0].Rows.Find(idProducto);
if (row != null) return true;
else return false;
}
public int NumeroDeLineas
{
get
{
return lineasPedido.Tables[0].Rows.Count;
}}}

Carga de un CEN sin CRUD


El cliente invoca directamente a un
Componente de Acceso a Datos (CAD)
quien se encarga de poblar el CEN
// Creamos un ProductoCAD
ProductoCAD cadProducto = new ProductoCAD();
// Usamos un ProductoCAD para obtener y poblar un
ENProducto
// Este código asume que ProductoCAD tiene un método //
GetProducto que toma un idProducto como parámetro (p.e. //
21) y devuelve un ENProducto con todos sus datos.
ENProducto producto = cadProducto.GetProducto (21);
// Cambiamos el nombre de este producto
producto.Nombre = Café tostado";
Ventajas y Desventajas de un CEN
!  Ventajas:
"  Legibilidad del Código. Usas la nomenclatura definida en tú
dominio del problema
"  Encapsulación. Permite realizar reglas de negocio sobre datos
que tiene en memoria sin tener que acceder a la BD
"  Modelado de sistemas complejos. Que requiere la
interoperabilidad entre diferentes objetos
"  Permite establecer campos privados
!  Desventajas:
"  Debes implementar manualmente su serialización
"  Ordenación y búsqueda manual
"  Extensibilidad. Si la BD se modifica debes modificar las clases

Definiendo Componentes de Entidad de Negocio con CRUD

!  Propone la encapsulación de las llamadas a


los CAD en el propio EN, evitando que sean
invocados desde el cliente

!  El cliente debe crear un EN y entonces invocar


al método CRUD
Representación de una CEN con CRUD en .NET
public class ENProductoCRUD
{
// Campos privados para mantener el
// estado de la Entidad Producto // Propiedades
private int idProducto; get { return nombre; }
private string nombre; set { nombre = value; }
private string cantidad; }
private decimal precioUnitario; public string Cantidad
// CAD que da acceso a la BD {
private ProductoCAD cadProducto; get { return cantidad; }
// Constructor set { cantidad = value; }
public ENProductoCRUD (int pidProducto, string nombre, string }
cantidad, decimal precioUnitario) { public decimal PrecioUnitario
cadProducto = new ProductoCAD(); {
idProducto = pidProducto; get { return precioUnitario; }
//..resto de atributos set { precioUnitario = value; }
} }

Representación de una CEN con CRUD


Métodos CRUD que reenvían la llamada a un CAD
// métodos CRUD
public AlmacenarProducto () {
cadProducto.CrearProducto (idProducto, nombre, cantidad, precioUnitario)
}

public ActualizarProducto () {
cadProducto.ActualizarProducto (idProducto, nombre, cantidad, precioUnitario)

}
public BorrarProducto() {
cadProducto.BorrarProducto (idProducto);
}
Ventajas de un CEN con CRUD
!  Ventajas:
"  Encapsulación. El CEN encapsula las operaciones definidas por
un CAD
"  Interfaz para el Cliente. El cliente debe tratar solo con un interfaz
para hacer persistente los CEN. No hay necesidad de acceder
directamente al CAD
"  Campos privados. Permite ocultar información que no quieres
exponer al cliente
!  Desventajas:
"  Tratar con colecciones de EN. Los métodos de un CEN
pertenecen a una única instancia. Para soportar colecciones,
debes definir métodos estáticos que devuelven un array o
colección de entidades
"  Se incrementa el tiempo de desarrollo. La aproximación
tradicional orientada a objetos requiere de más diseño y
esfuerzo de desarrollo que cuando se trabaja con estructuras
existentes como DataSets

Você também pode gostar