Prev - Next - Down | SDMetrics - the UML design measurement tool |
The symmetric difference of two sets A and B is the set of elements contained in either A or B, but not both. For regular sets, we could express the symmetric difference in terms of the existing set operations as (A+B)-(A*B) (i.e., the union of the sets without the intersection of the sets, see Section 8.5.3 "Set Expressions"). For multisets, however, we must take the cardinality of elements into account: the cardinality of an element in the symmetric difference is the absolute difference of the cardinality of the element in sets A and B. For example, if the cardinality of element e is five in set A and three in set B, the cardinality of element e in the symmetric difference is two. The formula (A+B)-(A*B) would yield cardinality (5+3)-3=5 for element e and therefore cannot be used for multisets.
The following implementation handles both regular and multisets.
packacke com.acme; import java.util.Collection; import java.util.Iterator; import com.sdmetrics.math.ExpressionNode; import com.sdmetrics.metrics.MetricTools; import com.sdmetrics.metrics.SDMetricsException; import com.sdmetrics.metrics.SetOperation; import com.sdmetrics.metrics.Variables; import com.sdmetrics.model.ModelElement; 01 public class SetOperationSymmDiff extends SetOperation { @Override 02 public Collection<?> calculateValue(ModelElement element, ExpressionNode node, Variables vars) throws SDMetricsException { 03 Collection<?> left = evalSetExpression(element, node.getOperand(0), vars); 04 Collection<?> right = evalSetExpression(element, node.getOperand(1), vars); 05 boolean isMultiSet = MetricTools.isMultiSet(right) || MetricTools.isMultiSet(left); 06 Collection<?> result = MetricTools.createHashSet(isMultiSet); // process elements from the first set 07 Iterator<?> it = MetricTools.getFlatIterator(left); 08 while (it.hasNext()) { 09 processElement(it.next(), result, left, right); } // process additional elements from the second set 10 it = MetricTools.getFlatIterator(right); 11 while (it.hasNext()) { 12 Object o = it.next(); 13 if (!left.contains(o)) { 14 processElement(o, result, left, right); } } 15 return result; } @SuppressWarnings({ "unchecked", "rawtypes" }) 16 private void processElement(Object o, Collection col, Collection<?> left, Collection<?> right) { 17 int leftCount = MetricTools.elementCount(left, o); 18 int rightCount = MetricTools.elementCount(right, o); 19 int count = Math.abs(leftCount - rightCount); 20 for (int i = 0; i < count; i++) 21 col.add(o); } }Once more, we discuss the salient features of this implementation, line by line.
<setoperationdefinition name="symmdiff" class="com.acme.SetOperationSymmDiff" />Again, we deploy the class file of the class in the "bin" folder of our SDMetrics installation (path com/acme/SetOperationSymmDiff.class). After that, we can write set expressions using the new function. For example:
<metric name="FooBar" domain="package"> <compoundmetric term="size(symmdiff(FooBarClassesSet, FooBazClassesSet))" /> </metric>
Prev | Up | Next |
Section 9.5 "Scalar Functions" | Contents | Section 9.7 "Metrics Engine Extension Guidelines" |