UNC COMP 301 - F26/Lec 11 - UML; Creational Design Patterns: Singleton, Multiton, Factory
Watch on YouTube →
Overview
Muhammad Sayeed Ghani introduces UML class diagrams, then explains three creational patterns: Singleton for one shared instance, Multiton for one instance per unique key, and Factory Method for centralizing subclass creation. Examples include a camera, students indexed by UNC PID, and email or text notifications; the lecture closes by showing how inheritance across multiple features can cause exponential class explosion.
Key takeaways
- UML uses hollow-triangle arrows for inheritance or interface implementation, but solid versus dotted lines distinguish class inheritance from interface realization.
- A composition relationship uses a filled diamond at the owning class, while aggregation uses a hollow diamond; multiplicity such as 0..* specifies how many related objects may exist.
- A Singleton combines a private constructor, a static stored instance, and a public static accessor that creates the object only when the stored reference is null.
- A Multiton maps a unique key such as a UNC PID to an object and checks whether the key already exists before creating another instance.
- Factory Method moves subclass-selection logic from multiple clients into one centralized creator, reducing duplicated notification-preference checks.
- When n independent features each have m options, inheritance subclasses for every combination can grow to mⁿ; Dog size and hair length with three options each already produce nine classes.
Chapters
- Ghani introduces UML as a way to visualize how classes and interfaces are structured as software grows more complex.
- The course example builds on a university course model and adds a Person interface, an abstract implementation, and a Roster class.
- The lecture establishes UML as a recurring tool for understanding design-pattern code later in COMP 301.
- A UML class rectangle has compartments for the class name, fields, and methods; interfaces may omit the fields compartment.
- Visibility symbols are + for public, − for private, # for protected, and ~ for package-default access.
- Field notation gives visibility, name, and type; method notation adds parameters and return type, while constructors omit a return type.
- Person is an interface with getName and getStatus, while PersonImple is an abstract class that implements it and stores a private String name.
- Italicized names identify abstract classes and interfaces that cannot be directly instantiated.
- A dotted line ending in a hollow triangle represents interface implementation; a solid line with a hollow triangle represents class inheritance.
- Student and Professor inherit from PersonImple and implement Person, while UML lists their own fields and methods rather than inherited members.
- Course receives its Professor through its constructor, so the Professor is created externally and participates in an aggregation relationship.
- Course creates its Roster internally, making the Roster a composition-owned object.
- A hollow diamond represents aggregation and a filled diamond represents composition; place the diamond beside the class that owns or contains the field.
- Multiplicity notation records quantity, such as one Professor per Course and one Roster per Course.
- Roster aggregates externally created Student objects, so students can outlive the roster that references them.
- Multiplicity 0..* means a roster may contain zero or more students; the course-to-roster relationship is one-to-one.
- Main depends on Student, Professor, and Course, shown with dotted arrows toward the classes it uses or creates; it has no direct dependency on internal Roster or Person implementation details.
- Ghani's suggested diagram workflow is to draw interfaces and superclasses first, then inheritance, aggregation or composition, and finally dependencies.
- Creational design patterns control object creation instead of relying everywhere on direct use of Java's new operator.
- Singleton is useful when software needs one shared instance, such as a finite camera or printer-spooler resource.
- A costly resource such as a large database or language model can be loaded once and reused rather than repeatedly initialized.
- A centralized logger is another example where multiple components should share the same object.
- A private FrontCamera constructor prevents code outside the class from creating camera instances directly.
- A public static create method provides access without requiring an existing object, avoiding the chicken-and-egg problem of calling an instance method.
- A static field of type FrontCamera stores the single shared instance.
- The create method constructs the camera only when the stored reference is null; later calls return the existing reference.
- Three calls to FrontCamera.create return references to the same object rather than creating three cameras.
- The UML shows FrontCamera implementing Camera, a static singleton field, and a static create method.
- Singletons can behave like global variables, and hard-coding a one-instance assumption can make later changes difficult—for example, supporting phones with two front cameras.
- Use Singleton only when the requirement for exactly one instance is expected to remain valid.
- Multiton allows multiple objects overall but restricts creation to one object for each key, unlike Singleton's one object for the entire class.
- A student system should not create duplicate Student objects for the same person when they return years later in a different program.
- A stable unique identifier such as a UNC PID distinguishes people with similar names and prevents duplicate records.
- A map from PID to Student provides the lookup structure needed to enforce one object per identifier.
- Student stores a static HashMap<Integer, Student> directory that maps each PID to its Student object.
- A static getStudent method checks containsKey before creating and registering a Student from the PID and name fields.
- If a PID already exists, the method can throw an exception or return the existing Student instead of overwriting the map entry.
- The sample requests PIDs 10, 20, and 20, so the directory should contain two Student objects after the repeated PID returns the existing entry.
- Factory Method addresses where subclass creation logic lives; unlike Singleton and Multiton, it does not limit the number of objects.
- Students have notification preferences represented by an enum with TEXT, EMAIL, and PUSH options.
- An abstract Notification class has concrete subclasses such as TextNotification and EmailNotification.
- Without a factory, each caller checks a student's preference and duplicates the conditional logic that chooses a notification subclass.
- A static factory method accepts a Student and selects the matching notification subclass based on that student's preference.
- Client code now passes students to the factory rather than repeating checks and directly constructing TextNotification or EmailNotification.
- Centralizing subclass selection makes changes—such as adding a notification type or changing selection rules—easier to maintain.
- The Notification factory example preserves the Student and notification subclasses while changing which class is responsible for creating them.
- In the non-factory UML, the client depends directly on TextNotification and EmailNotification and contains preference-selection logic.
- With Factory Method, Notification depends on and creates the concrete subclasses; the client uses Notification without directly choosing a subclass.
- Singleton ensures one instance per class, Multiton ensures one instance per unique key, and Factory Method centralizes subclass instantiation.
- All three patterns centralize some part of object creation, but they solve different creation problems.
- The lecture revisits the principle of preferring composition or aggregation over inheritance when object features vary independently.
- A Dog example has two features—size and hair length—with three choices each: small, medium, or large and short, medium, or long.
- Representing every combination as an inheritance subclass requires 3² = 9 classes for only two features.
- With m options for each of n features, the number of combination subclasses grows as mⁿ, motivating composition-based designs.
- The Dog example shows that adding independent size and hair-length variations rapidly expands the inheritance hierarchy.
- Three options for each of two features already require nine specialized subclasses, such as a medium dog with short hair.
- Ghani concludes that inheritance is a poor fit for multiplying feature combinations and previews composition and aggregation in later patterns.
Summary, takeaways, and chapters were generated by AI from the video's transcript and may contain errors. The video belongs to its creator, Muhammad Sayeed Ghani.