Contents
UML constructors document the API. Attributes and the line between classes document the structure. Passing x, y does not mean you are design 1. Instantiating Point inside the constructor does not mean you are design 2.
API vs structure
In that sentence, API is how you use the class. Structure is what the class is made of.
API (application programming interface) here is not a web API. It is the public surface of the class: constructors, methods, and properties that other code is allowed to call. In UML, the constructor line documents that surface:
+ Circle(radius : double)
+ Circle(radius : double, centerX : double, centerY : double, color : string)
That answers: “What do I write in new Circle(...)?”
Structure is the internals and the relationships: fields, and the line from Circle to Point. In UML that is the attribute compartment plus the association or composition line:
- _center : Point
Circle → Point
That answers: “What does a circle contain, and how is it connected to other classes?”
| Question | UML shows it with | |
|---|---|---|
| API | How do I create / talk to a Circle? |
constructors, + operations |
| Structure | What is inside a Circle, and what does it know? |
attributes, the line between classes |
They can disagree. Design 3’s constructor (API) takes two numbers. Its structure is still a Point (_center) and a composition line. UML needs both: the constructor for how you create it, the attributes and the line for what you actually built.
Constructor parameters vs attributes
What you pass into new Circle(...) is not the same decision as what Circle stores. Those are two separate design choices:
- Constructor parameters — the arguments of
new Circle(...). Numbers? APoint? - Attributes — the fields on the object after it exists. Two
doubles? APoint?
Those can match, or they can differ.
| Design | You pass in | Circle stores |
|---|---|---|
| 1 | x, y (numbers) |
_centerX, _centerY (numbers) |
| 2 | a Point |
_center (Point) |
| 3 | x, y (numbers) |
_center (Point) — created inside |
In 1 and 2, parameters and attributes line up: you pass what you keep.
In 3 they do not. You still write new Circle(3, 1, 4, "green"), but the constructor does _center = new Point(centerX, centerY). The UML follows the attributes (there is a Point), not the parameter list.
Do not assume that because the constructor takes x and y, the class has CenterX and CenterY. The constructor is the public way to create the object. The attributes are the internal model.
UML notation
The diagrams below use this notation. Design 2 is a one-way association (solid line, arrow toward Point). Design 3 is composition (filled diamond on Circle) with the same arrow toward Point.
Design 1. Pass and store x, y (no Point)
The centre is two numbers stored inside Circle. There is no Point object and no relationship between classes.
private double _centerX;
private double _centerY;
public Circle(double radius, double centerX, double centerY, string color)
{
_radius = radius;
_centerX = centerX;
_centerY = centerY;
_color = color;
}
public Circle(double radius) : this(radius, 0, 0, "white") { }
// creating a circle
new Circle(3, 1, 4, "green");
new Circle(6);
Coordinates are accessed as circle.CenterX and circle.CenterY. Each circle has its own copies of the numbers, so changing one centre never moves another circle.
Design 2. Pass a Point reference (store that reference)
The centre is a separate object that Circle refers to. You create the Point first and pass that object into the constructor. This is a has-a relationship: a circle has a centre point.
public Point(double x, double y) { /* … */ }
private Point _center;
public Circle(double radius, Point center, string color)
{
_radius = radius;
_center = center; // store the Point that was passed in
_color = color;
}
public Circle(double radius) : this(radius, new Point(), "white") { }
// creating a circle
Point p = new Point(1, 4);
new Circle(3, p, "green");
new Circle(6);
Point. The arrow points the way you can navigate: Circle can use Point (circle.Center.X); Point knows nothing about Circle. Multiplicity * … 1: a circle has one centre; several circles may use the same point. A filled diamond would mean composition. This is the chapter 3 design in the Geometry practica.Coordinates are accessed as a chain: circle.Center.X and circle.Center.Y. Because Point is a reference type, two circles can share one point:
Point p = new Point(1, 4);
Circle c1 = new Circle(3, p, "green");
Circle c2 = new Circle(5, p, "blue");
p.X = 10; // both circles move
Design 3. Pass x, y, instantiate Point inside Circle
You pass numbers, as in design 1. Internally Circle still stores a Point, as in design 2. Circle itself creates that object, so two circles cannot share the same point through this constructor.
public Point(double x, double y) { /* … */ }
private Point _center;
public Circle(double radius, double centerX, double centerY, string color)
{
_radius = radius;
_center = new Point(centerX, centerY); // Circle creates it
_color = color;
}
public Circle(double radius) : this(radius, 0, 0, "white") { }
// creating a circle — same new Circle(...) as design 1
new Circle(3, 1, 4, "green");
new Circle(6);
Circle (the owner), arrow on Point (the part). The diamond means the point does not live on without the circle. The arrow means the same navigability as UML 2: Circle can use Point; Point knows nothing about Circle. Multiplicity 1–1: each circle owns exactly one centre, created inside the constructor. The constructor takes numbers, like (1); the stored type is Point, like (2).If you keep a public Center setter that accepts an existing Point, sharing becomes possible again and a one-way association (arrow toward Point, * … 1) is more honest. The filled diamond is justified only if Circle always creates the point and the point is destroyed with the circle.
Design 2 in the Geometry practica also has an extra constructor that creates a Point inside Circle:
public Circle(double radius) : this(radius, new Point(), "white") { }
The difference with design 3 is not “does this constructor call new Point()?”. It is what the class as a whole allows.
Design 2 still has a constructor that accepts an existing Point:
public Circle(double radius, Point center, string color)
{
_center = center; // store the Point that was passed in
}
The radius-only constructor is an extra path into the same storage. After that it is still design 2: _center may be a Point that lives outside the circle, and that Point may be shared.
Design 3 has no constructor (and in the pure variant no setter) that takes an existing Point. Only numbers. Each circle gets a Point that Circle itself creates. Through that API you cannot share a Point.
UML follows that object relationship of the class, not one constructor line. One convenience constructor that does new Point() does not change the diagram. As long as the class also has Circle(..., Point center, ...), Circle knows a Point but does not exclusively own it. Composition (filled diamond) is justified only if Circle always creates the Point and the point dies with the circle.
| (2) Pass Point | (3) Pass x, y, new Point inside | |
|---|---|---|
| What Circle stores | a Point reference |
a Point reference |
| Can you inject an existing Point? | yes | no |
| Two circles share one location object? | yes (* … 1) |
no (1 … 1) |
| UML | Circle * → 1 Point (arrow toward Point) |
filled diamond Circle 1 ◆→ 1 Point (arrow toward Point) |
Side-by-side
| (1) Store x, y | (2) Pass Point | (3) Pass x, y, new Point inside | |
|---|---|---|---|
| Constructor args | primitives | Point |
primitives |
| What Circle stores | two doubles |
a Point reference |
a Point reference |
| Point class needed? | no | yes | yes |
| UML | one class | Circle * → 1 Point (arrow toward Point) |
filled diamond Circle 1 ◆→ 1 Point (arrow toward Point) |
| Relationship | none | one-way association | composition (one-way, owned part) |
| Who creates the centre | nobody (just numbers) | the code that writes new Circle(...) |
Circle |
| Two circles share one location object? | n/a (values copied) | yes | no (each new is a new object) |
| You write | new Circle(3, 1, 4, "green") |
new Circle(3, new Point(1, 4), "green") |
new Circle(3, 1, 4, "green") |
| Access coordinates | circle.CenterX |
circle.Center.X |
circle.Center.X |
| Change one circle’s centre | only that circle | all circles that share the Point |
only that circle |
| Reuse Point on Rectangle etc. | duplicate x, y on every shape | yes | yes |
What is actually different
(1) vs (3) — same new Circle(3, 1, 4, "green"), different model
new Circle(3, 1, 4, "green");
In (1) those numbers live on Circle. In (3) Circle immediately wraps them in a Point. UML therefore changes: (3) still has the Point class and a line between the boxes. (1) does not.
(2) vs (3) — same model, different creation policy
Both store _center : Point. UML class boxes are the same. The differences are the constructor (Point vs two doubles), a one-way association vs one-way composition (plain arrow vs filled diamond plus arrow), and whether p.X = 10 can move several circles.
Point p = new Point(1, 4);
Circle a = new Circle(3, p, "green"); // (2) a.Center is p
Circle b = new Circle(3, 1, 4, "green"); // (3) b.Center is a new Point(1,4)
p.X = 10; // a moves; b does not
Point you passed in. Design 3 always allocates a new Point.You can offer both (2) and (3)
Overloading makes the two creation policies explicit. Same stored model, two APIs:
public Point(double x, double y) { /* … */ }
// sharing possible: you pass in an existing Point
public Circle(double radius, Point center, string color)
{
_radius = radius;
_center = center;
_color = color;
}
// no sharing at construction: Circle owns a fresh Point
public Circle(double radius, double x, double y, string color)
: this(radius, new Point(x, y), color)
{
}
public Circle(double radius) : this(radius, new Point(), "white") { }
How to read the diagrams
- (1) and (3) can have the same constructor in the diagram and still differ in attributes.
- (2) and (3) can have the same
_center : Pointand still differ in constructor and in one-way association vs one-way composition. Both arrows point towardPoint. Only (3) has the filled diamond onCircle. - Parameters ≠ attributes. UML shows structure: “does
Circlehave aCenterof typePoint?” It does not show whether thatPointwas passed in or created inside the constructor. - A constructor that does
new Point()internally does not make the class composition. UML follows what the class as a whole allows: can an existing Point be injected and shared?
Which one the Geometry practica uses
Chapters 1–2
Design (1): Circle(radius, centerX, centerY, color) with primitive CenterX / CenterY.
Chapter 3 onward
Design (2): Circle(radius, Point center, color). The radius-only constructor resembles design (3) (new Point() internally), but UML stays a one-way association: the main constructor still accepts a Point. Design (3) as the all-args constructor is a valid extra overload; it is not the main design after chapter 3.
Glossary
Underlined words appear here. Hover a word in the page to see this explanation.