Acoplamiento y cohesión:
las dos piedras angulares de la programación OO
(Extractado de: http://javaboutique.internet.com/tutorials/coupcoh/)
por Gupta Samudra
de programación orientado a objetos tiene dos objetivos principales: la construcción de clases de gran cohesión y de mantener bajo acoplamiento entre las clases. Highcohesion medios bien estructurados clases y acoplamiento flexible significa más flexible, el software extensible. La aplicación de las métricas a objetos para el diseño y el código puede ayudar a determinar si usted ha logrado estos objetivos.
¿Qué es la cohesión?
En OO metodología, las clases contienen ciertos datos y exhiben ciertos comportamientos. Este concepto puede parecer obvio, pero en la práctica, la creación de clases bien definida y coherente puede ser complicado. Cohesiva significa que una cierta clase realiza una serie de acciones estrechamente relacionadas. La falta de cohesión, por el contrario, significa que una clase es realizar varias tareas relacionadas. A pesar de la falta de cohesión no puede tener un impacto en la funcionalidad global de una clase o de la propia aplicación, el software de aplicación con el tiempo van a ser incontrolables como los comportamientos más y más se dispersan y terminan en lugares equivocados.
Así, uno de los principales objetivos de diseño orientado a objetos es llegar a las clases que son altamente cohesivo. Por suerte, hay una métrica para ayudar a youverify que ha diseñado una clase cohesionada.
La LCOM METRIC : La falta de cohesión en los métodos
La falta de cohesión en el sistema métrico métodos está disponible en los siguientes tres formatos:
LCOM1: Tome cada par de métodos de la clase y determinar el conjunto de campos que cada acceso. Si se han desarticulado grupos de acceso a campo, el número aumenta P por uno. Si comparten al menos un acceso de campo, Q aumenta en uno. Después de considerar cada par de métodos:
RESULT = (P > Q) ? (P - Q) : 0
Un valor bajo indica un alto acoplamiento entre los métodos. Esto también indica la reutilización de elevado potencial y el diseño de buena clase. Chidamber Kemerer y siempre que la definición de este indicador en 1993.
LCOM2: Esta es una versión mejorada del LCOM1. Diga que lo definen los siguientes elementos en una clase:
m: number of methods in a class
a: number of attributes in a class.
mA: number of methods that access the attribute a.
sum(mA): sum of all mA over all the attributes in the class.
LCOM2 = 1- sum(mA)/(m*a)
Si el número de métodos o variables en una clase es cero (0), LCOM2 no está definido como se muestra como cero (0).
LCOM3: Esta es otra de las mejoras en LCOM1 y LCOM2 y se ha propuesto por Henderson Sellers. Se define de la siguiente manera:
LCOM3 = (m - sum(mA)/a) / (m-1)
where m, a, mA, sum(mA) are as defined in LCOM2.
Los siguientes puntos deben tenerse en cuenta sobre LCOM3:
• El valor LCOM3 varía entre 0 y 2. LCOM3> 1 indica que la falta de cohesión y es considerado una especie de alarma.
• Si sólo hay un método en una clase, FCM 3 es indefinido y si no hay atributos en un LCOM3 clase también es indefinido y se muestra como cero (0).
Cada una de estas diferentes medidas de la FCM tiene una manera única para calcular el valor de la FCM.
• Una extrema falta de cohesión como LCOM3> 1 indica que la clase particular, debe dividirse en dos o más clases.
• Si todos los miembros de los atributos de una clase son accesibles únicamente fuera de la clase y nunca acceder dentro de la clase, LCOM3 mostrará una highvalue.
• Un valor ligeramente alto de la FCM significa que usted puede mejorar el diseño, ya sea dividir las clases o reorganizar ciertos métodos dentro de un conjunto de clases.
Un ejemplo concreto
Listing 1 define una clase de orden para los que puede aplicar la métrica FCM.
La Figura 1 muestra un alto nivel del modelo UML de un imaginario sistema de procesamiento de pedidos.
Figura 1: Muestra un diagrama de clases UML para un Sytem de procesamiento de pedidos. Nota: El diagrama de ejemplo UML y el código fuente a continuación es solo un ejemplo y presentar un
gran ejemplo de código en bruto. Por favor, no intente volver a utilizar esta clase para cualquier proyecto real.
Para aplicar el LCOM3 métricas a la clase Order, definir las variables métricas de la siguiente manera:
m(number of methods in the class) = 4
a(number of attributes in the class)=5
m[prod] = number of methods accessing the attribute prod = 3 m[orderNumber] = number of methods accessing the attribute orderNumber= 2m[totalAmount] = number of methods accessing the attribute totalAmount = 4 m[deliveryType] = number of methods accessing the attribute deliveryType = 2 m[underPromotion] =number of methods accessing the attribute underPromotion=3
Therefore:
LCOM3 = ( m - sum(mA)/a ) / (m - 1)
= ( 4 - 14/5 ) / (4-1)
= 0.73
Recuerde que debe contar también el constructor como un método de la clase en este cálculo.
El análisis FCM en la clase Order reveló que había un nivel razonablemente alto de cohesión no. Aunque, no es "alarmante" (como los valores de> 1 sería alarmante según LCOM3), que sería conveniente para mejorar su diseño.
Un poco de inspección de todos los métodos de la clase inmediatamente se ponen de manifiesto que el método checkIfProductExists () no es una buena opción para esta clase. La clase de orden debe encapsular los comportamientos que una Orden tendrá que exhibir. Básicamente, se supone que cuando una instancia de la Orden se crea, el producto en sí es un producto válido y vigente. La responsabilidad de asignar un producto válido para el objeto Orden está en mejores condiciones como parte de la clase OrderManager.
Después de quitar el checkIfProductExists () de la clase Order, volver a calcular el valor de LCOM3:
m(number of methods in the class) = 3
a(number of attributes in the class)=5
Therefore:
LCOM3 = ( m - sum(mA)/a ) / (m - 1)
= ( 3 - 13/5 ) / (3-1) ***Note: sum(mA) is now reduced by one.
= .20
Esta clase es ahora más coherente, con un valor de 0,20 FCM-en comparación con el valor anterior de 0.73. Ese simple cambio hizo un mundo de diferencia en la paz de la mente.
Medición de acoplamiento
El acoplamiento es una palabra que suele utilizarse de forma despectiva en las reuniones de revisión del diseño. Aun así, no es posible diseñar una aplicación OO funcional sin acoplamiento. Cada vez que un objeto interactúa con otro objeto, que es un acoplamiento. En realidad, lo que hay que tratar de minimizar los factores de acoplamiento es. Acoplamiento fuerte significa que un objeto está fuertemente unido a los detalles de implementación de otro objeto. Acoplamiento fuerte se siente desanimado porque el resultado es menos flexible, menos la aplicación de software escalable. Sin embargo, el acoplamiento se puede utilizar de modo que permite a los objetos se comuniquen entre sí al mismo tiempo preservar la escalabilidad y flexibilidad.
Aunque esto parece una tarea difícil, las métricas OO te puede ayudar a medir el nivel adecuado de
acoplamiento.
• Acoplamiento entre objetos (CBO): CBO se define como el número de clases no hereditarias asociadas con la clase de destino. Se cuenta que el número de tipos que se utilizan en los atributos, parámetros, tipos de cambio, arroja cláusulas, etc tipos primitivos y tipos de sistemas (por ejemplo, java.lang .*) no se cuentan.
• Los datos de abstracción de acoplamiento (CAD): CAD se define como el número total de especies contempladas en las declaraciones de atributos. Los tipos primitivos, tipos de sistemas, y los tipos heredados de la clase super no se cuentan.
• Método de Invocación de acoplamiento (MIC): se define como el número relativo de las clases que reciben los mensajes de una clase en particular.
MIC = nMIC / (N-1)
Donde n = número total de clases definidas en el proyecto. nMIC = número total de clases que reciben un mensaje de la clase de destino.
Ley de Deméter
Ian Hollaand propuso por primera vez la Ley de Demeter. La forma de clase de la Ley de Deméter tiene dos versiones: una versión estricta y una versión de minimización. La forma estricta de la ley establece que todas las clases de proveedor de un método debe ser el proveedor preferido. La forma de minimización es más permisiva que la primera versión y sólo requiere reducir al mínimo el número de clases de conocimiento de cada método.
• Definición 1 (clientes): Método M es un cliente del método f adjunta a la clase C, si dentro de mensaje M f es enviado a un objeto de clase C, o C. Si f está especializada en una o más subclases, entonces M sólo es un cliente de f adjunta a la clase más alta en la jerarquía. Método M es un cliente de algún método adjunta a C. En la Lista 1, el constructor de la clase Order es un cliente de la clase del producto, ya que llama a la getPrice () de la clase del producto.
• Definición 2 (Proveedor): Si M es un cliente de clase C, entonces C es un proveedor de M. En otras palabras, una clase de proveedor a un método es una clase cuyos métodos son llamados en el método. En la Lista 1, la clase de producto es una clase de proveedor de la Orden de clase de cliente.
• Definición 3 (Conocido clase): Una clase C1 es una clase de conocimiento del método M adjunta a la clase C2, C1, si es un proveedor de M y C1 no es uno de los siguientes:
• • •
Al igual que C2;
una clase utilizada en la declaración de un argumento de clase M
A utilizados en la declaración de una variable de instancia de C2
En la Lista 1, del producto es una clase de conocimiento de la clase de pedido, porque el producto se declara
como una variable de instancia de la clase de pedido y también se pasa como argumento al constructor.
• Definición 4 (clase Preferredsupplier): Clase B se llama al método preferredsupplier M
(Que se adjunta a la clase C) si B es un proveedor de M y una de las siguientes condiciones se tiene:
• • •
B se utiliza en la declaración de una variable de instancia del banco central se utiliza en la declaración de un argumento de M, incluyendo C y sus superclases B es una clase de conocimiento preferido de M.
En la Figura 1, la clase OrderLine, Giro es una clase de proveedor preferido de la clase OrderManager ya que se utilizan como variables de instancia dentro de la clase OrderManager.
Un ejemplo concreto
En el imaginario ejemplo de procesamiento de pedidos, imagina que tienes el siguiente formulario de código en la clase OrderManager.
Class OrderManager {
Private Order order;
public void getOrderByCustomer()
{
int productPrice = order.prod.price
}
Se puede ver que la clase del producto se convierte en un proveedor de la clase OrderManager. Esto no está permitido de acuerdo a la forma estricta de la ley debido a Deméter producto no es un proveedor preferido para la clase OrderManager.
Pruebe lo siguiente:
Class OrderManager {
Private Order order;
public void getOrderByCustomer()
{
int productPrice = order.getProductPrice();
}
Tenga en cuenta que el código anterior hace que el supuesto de que OrderManager tratará con un solo pedido en una hora y el orden también que uno puede tener un solo producto.
En el código modificado, la clase OrderManager cliente no necesita saber cómo funciona el modelo de objetos se encuentra entre la Orden y del producto. Además, nunca ha utilizado o inicializar la clase de producto dentro de la clase OrderManager. Tener que hacer referencia a la clase del producto indirectamente para conseguir el precio es una violación a la Ley de Demeter.
La figura 2 presenta un diagrama UML corregido con todos los cambios que se han hecho hasta ahora.
Figura 2: La corrección de diagramas UML. Todo lo que se suma a
Todos estos parámetros de acoplamiento realmente cumplen la misma función: para reducir las dependencias entre las varias clases. La dependencia menor, mayor será la probabilidad de una solución más flexible. Pero en la programación OO, el acoplamiento es inevitable. Por lo tanto, el objetivo es reducir las dependencias innecesarias y hacer las dependencias necesarias coherente. En el ejemplo de este artículo, la clase OrderManager sigue siendo, junto a las clases OrderLine y Orden, pero su acoplamiento innecesarios con la clase de productos se ha eliminado.
No nos equivoquemos, estos indicadores son fundamentales para medir la calidad de una aplicación.
Listing 1: An Imaginary Order Class
public class Order {
private boolean underPromotion;
private String deliveryType;
private int totalAmount;
private int orderNumber; private Product prod;
public Order(Product prod, String deliveryType, boolean underPromotion) {
this.prod = prod;
this.deliveryType = deliveryType;
this.underPromotion = underPromotion;
this.totalAmount = prod.getPrice();
this.orderNumber = 100; // we will actually assign a number here.
}
public int getPromotionalPrice() {
if (underPromotion) {
totalAmount = totalAmount 6;
}
return totalAmount;
}
public boolean checkIfProductExists()
{
return prod != null;
}
public String getOrderInfo()
{
return prod.toString()+orderNumber+totalAmount+deliveryType+underPromotion;
}
public int getOrderPrice()
{
if (deliveryType.equalsIgnoreCase("special"))
{
totalAmount = totalAmount + 6;
}
return totalAmount;
}
}
No hay comentarios:
Publicar un comentario