The Design Analyzer

The Design Analyzer (DA) computes and displays several design metrics for all of the classes in some user specified package.

The DA Metrics

For every class, A, in the specified package, the design analyzer computes and displays the following design metrics:

instability(A)
responsibility(A)
inDepth(A)
workLoad(A)

Where:

instability(A) = #providers(A)/#P
responsibility(A) = #clients(A)/#P

However, DA defines class X to be a client of class Y if the interface of X references Y. The interface of a class is the class without its method implementations. In other words, X references Y if X contains a field, parameter, or return type of type Y. This means that we don't need to consider local variables or implicit references inside of X.

The inheritance depth of class A, inDepth(A), is the number of superclasses of A in the package. Recall that B is a superclass of A if A is a subclass of B. Also recall that A is a subclass of itself. A class with a relatively large inheritance depth is difficult to understand, use, and replace.

The workload of a class is the number of methods in the class (scope doesn't matter) divided by the number of methods in the package. Generally speaking, all classes should have about the same workload.

Example

DA assumes the parent directory of the user-specified package is on the classpath and that the user has specified the path to the package at the command prompt.

For example, assume the demo package is located in the directory C:\projects. Also assume that C:\projects is on the classpath. Here is how the design analyzer is invoked on the demo package:

java DA c:\\projects\\demo

In this example the demo package consists of seven classes, A – F and Demo:

Demo.java

Here's a class diagram of the demo package:

Note that the dashed dependency arrows are being used to indicate the types of the method parameters.

Also note that in the demo package there are 7 classes and 14 methods,

The output of DA is:

C     inDepth(C)     instability(C) responsibility(C)     workload(C)

A        1              0                 .28                 .14
B        2              .14               .28                 .14
C        3              .14               0                   .28
D        1              .14               .28                 .07
E        1              .28               .14                 .14
F        1              .28               0                   .14
Demo     1              0                 0                   .07

Note that decimals are rounded off to two places. (Use System.out.printf for this.)

Design and Implementation

The design of DA is pretty simple:

Note that there are separate methods for computing each metric, for displaying the results, and for loading the package from the pathname. (Some methods are shown to be private, but should be public.)

DA depends heavily on Java reflection, which is covered in reflection.htm.

The package is a set of class objects:

Set<Class> package;

This set must be initialized and loaded by the loadPackage method:

void loadPackage(String path) {
   package = new HashSet<Class>();
   File[] files = all .class files in path;
   for(int i = 0; i < files.length; i++) {
      get the name of files[i];
      drop the extension;
      prepend the package name;
      use the class.forName to load the class;
      add the class to the package;
   }
}

The main method is simple:

DA da = new DA();
da.loadPackage(args[0]);
da.displayMetrics();

Grading

Test your design analyzer on the demo package, but don't hardwire this package into your program. I will create a different package with a different name and test your design analyzer on it.

Enhancements

1. Add a graphical user interface to DA. This could simply be a JPanel with a JMenu that allows the user to select and load a package using a file dialog, and another menu item for displaying the metrics. Ideally, the metrics can be displayed in a JTable.

2. (Extra Credit) Use my graphing utilities to create and display the dependency graph for the package.