OOP · Geometry · Circle and Point

Three ways to give a Circle a centre

When you write new Circle(...), designs 1 and 3 look the same: you pass numbers. What Circle stores is different. Designs 2 and 3 both store a Point; they differ in who creates that object. Constructor parameters and attributes are two separate design choices.

This teaching note belongs with the Geometry practica in OOP in C#. There, Circle first stores numeric coordinates and later gets a Point as centre. The pages below show how that change looks in code and in UML.

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:

    1. Constructor parameters — the arguments of new Circle(...). Numbers? A Point?
    2. Attributes — the fields on the object after it exists. Two doubles? A Point?

    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.

    UML class diagram cheatsheet: package, interface, abstract class, class, inheritance, realization, association, one-way association, aggregation, composition, and note
    UML class diagram cheatsheet by Khalil Stemmler. Original: khalilstemmler.com.

    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);
    
    UML class diagram of Circle with primitive centerX and centerY attributes and no Point class
    UML 1. One class. Centre is primitive attributes. No line to another class — relationship: none.

    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);
    
    UML class diagram: one-way association from Circle to Point, arrow pointing at Point, multiplicity star to 1, role Center
    UML 2. One-way association: solid line with an arrow on 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);
    
    UML class diagram: composition from Circle to Point, filled diamond on Circle, arrow pointing at Point, multiplicity 1 to 1
    UML 3. Composition with direction: filled diamond on 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
    
    Memory: shared Point versus owned Point Circle a points at the same Point as variable p. Circle b points at a different Point with the same coordinates. After the two constructor calls Circle a (2) Center → Circle b (3) Center → Point p (1, 4) then X=10 new Point (1, 4) unchanged shared — a.Center is p owned — different object
    Sharing vs ownership. Design 2 stores the 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

    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.

    Top