scitools.com

← Graph catalog

UML Class Diagram is one of the interactive graphs Understand can draw of your code — call trees, dependencies, control flow, and more.

UML Class Diagram

Languages: Ada, C#, C++, Java, Python, Web
Targets: Architectures, Classes, Files, Packages, Record Types
Variants: Classic

Show a UML-style class diagram of a selected class, along with its base classes and subclasses.

For a class, show the UML-style class diagram of the selected class. For a file, architecture, or Python package, show the UML-style class diagram of all classes contained in it.

The main box lists the class's own fields and methods in UML notation — +/#/- prefixes for public/protected/private, name: type for fields (with an initializer after = when there is one), and name(params) returnType for methods. Its immediate base classes are added above the main box and its immediate subclasses below, connected by a hollow-triangle inheritance arrow pointing from subclass to base class. This only follows class inheritance (extends, or the equivalent in other languages) — it doesn't follow interface implementation, so a class's implemented interfaces never appear here.

See the Declaration graph for a more detailed view of the same class — it groups members the same way, but also includes nested types, and adds the interfaces a class implements (or, for an interface, the classes that implement it).

Rooted at the abstract class Shape below, the main box lists its private, protected, and public members in UML notation. Entity, its base class, is added above; Circle, its only subclass, is added below. Although Shape also implements Drawable and Renderable, neither interface appears, since this graph only follows class inheritance.

See the following code and corresponding graph

public abstract class Entity {
    private static int nextId = 0;

    protected final int entityId;

    protected Entity() {
        this.entityId = ++nextId;
    }

    public    int    getId()      { return entityId; }
    public abstract String describe();

    static int allocateId() { return ++nextId; }
}

public interface Drawable {
    void   draw();
    double area();
    default String drawDescription() { return "Drawable"; }
}

interface Renderable {
    void    render(float alpha);
    boolean isVisible();
}

public abstract class Shape
    extends Entity implements Drawable, Renderable {

    public enum Visibility { VISIBLE, HIDDEN, CLIPPED }

    public interface ShapeObserver {
        void onShapeChanged(Shape shape);
    }

    public static int maxShapes = 1000;

    public abstract double area();
    public abstract void   draw();

    public double  getX()          { return x; }
    public double  getY()          { return y; }
    public void moveTo(double nx, double ny) {
        x = nx; y = ny; updateBounds(); }
    public Visibility visibility() { return visibility; }
    public void    setVisibility(Visibility v) { visibility = v; }
    public void addObserver(ShapeObserver obs) { observers.add(obs); }

    public boolean isVisible()
        { return visibility == Visibility.VISIBLE; }
    public void    render(float alpha) { if (isVisible()) draw(); }

    public String describe() {
        return getClass().getSimpleName() + "(" + x + "," + y + ")"; }

    protected static class BoundingBox {
        public double minX, minY, maxX, maxY;
        BoundingBox(double x, double y, double w, double h) {
            minX = x; minY = y; maxX = x + w; maxY = y + h;
        }
    }

    protected double     x, y;
    protected Visibility visibility = Visibility.VISIBLE;
    protected BoundingBox bounds;

    protected abstract void  updateBounds();
    protected void           notifyObservers() {
        for (ShapeObserver o : observers) o.onShapeChanged(this);
    }

    private static class IdCounter {
        private static int count = 0;
        static int next() { return ++count; }
    }

    private int          shapeId;
    private int          refCount   = 0;
    private List<ShapeObserver> observers = new ArrayList<>();

    private void assignId()   { shapeId = IdCounter.next(); }
    private void retain()     { refCount++; }
    private void release()    { if (--refCount < 0) refCount = 0; }

    protected Shape(double x, double y) {
        super();
        this.x = x;
        this.y = y;
        assignId();
    }
}

public class Circle extends Shape {

    private double radius;

    public Circle(double x, double y, double radius) {
        super(x, y);
        this.radius = radius;
    }

    public double  getRadius()     { return radius; }
    public void    setRadius(double r) { radius = r; updateBounds(); }

    @Override
    public double area() { return Math.PI * radius * radius; }

    @Override
    public void    draw()          { }

    @Override
    protected void updateBounds()  {
        bounds = new BoundingBox(
            x - radius, y - radius, radius * 2, radius * 2);
    }
}