|
The depth of a type is the length of a longest path in the inheritance hierarchy from Object to the type.
The depth of a type is an indication of how deeply nested a type is in a
given design. Very deep types can be an indication of over-engineering, whereas a
system with predominantly shallow types may not be exploiting object-orientation
to the full.
This metric is often confused with
Number of Ancestors in Inheritance Hierarchy,
which counts all the ancestors, not just those on the longest path to Object.
The depth metric is used to compute the Specialization Index, which is a measure of
the extent to which subclasses override behavior in super classes.
Pre-packaged Query
Query name = "Semmle/Metrics/Types/Inheritance/RefTypes that are deep in the type hierarchy"
Reports reference types whose maximum distance to Object is greater
than 6, in decreasing order of distance, as a bar chart.
from MetricRefType t, int d
where t.fromSource() and d = t.getInheritanceDepth() and d > 6
select t, d order by d desc
.QL Source of Metric
This metric is defined in the class MetricRefType. We first compute
the length of some path to the root, non-deterministically. Next,
we take the maximum over all those lengths, to obtain the depth.
// find the length of *some* path to the root of the hierarchy
int getADepth() {
(this.hasQualifiedName("java.lang", "Object") and result=0)
or
(result = ((MetricRefType)this.getASupertype()).getADepth() + 1)
}
// compute depth of inheritance metric
int getInheritanceDepth() {
result = max(this.getADepth())
}
Note how the result of a getASupertype() is cast to
MetricRefType, so that the getADepth() method can be
called on it. To Java programmers, this may appear strange at first, but
remember that .QL classes are characterized by logical properties: casting
to a type is just checking that the value satisfies the property of being
a MetricRefType. In this example, since any RefType
is also a MetricRefType, that check will always succeed.
Variation
Spinellis defines this metric subtly differently, only counting
classes, not interfaces. To get Spinellis's definition,
we can override the above as follows:
class MyMetricRefType extends MetricRefType {
RefType getSuperClass() {
result = this.getASupertype()
}
int getADepth() {
(this.hasQualifiedName("java.lang", "Object") and result=0)
or
(result = ((MyMetricRefType)this.getSuperClass()).getADepth() + 1)
}
}
References
Shyam R. Chidamber and
Chris F. Kemerer.
A Metrics Suite for Object Oriented Design
.
IEEE Transactions on Software Engineering,
20(6), pages 476-493, June 1994.
Diomides D. Spinnelis.
Code Quality: The Open Source Perspective.
Addison-Wesley 2007.
Diomides D. Spinnelis.
ckjm - Chidamber and Kemerer Java Metrics.
(implementation of CK metrics), 2006.
|