Bird
Raised Fist0

UML Class Diagrams - Reading and Drawing Relationships, Multiplicity, Notation

LLDeasyInterview freq: common
Choose your preparation mode4 modes available
๐ŸŽฏ
UML Class Diagrams - Reading and Drawing Relationships, Multiplicity, Notation
40 min ยท medium
medium

Design a system to represent UML class diagrams focusing on relationships between classes. The system must support at least 5 levels of class hierarchy, 4 types of relationships (association, aggregation, composition, inheritance), multiplicity notation (1, 0..1, *, 1..*), and drawing/rendering these relationships with correct UML notation. The system should allow adding new relationship types without modifying existing code.

  • There are 4 primary relationship types: Association, Aggregation, Composition, Inheritance.
  • Multiplicity must be represented explicitly and validated (e.g., 1..*, 0..1).
  • Classes can have multiple relationships with multiplicities on both ends.
  • The system must support thread-safe updates to the diagram (adding/removing relationships).
  • Drawing relationships requires different line styles and arrowheads per relationship type.
  • Extensibility is required to add new relationship types without modifying existing classes.
๐Ÿ“‹
Guided Steps
1/5
Step 1
Define UML Class and Relationship Base Classes
Design the base classes for UMLClass and UMLRelationship. Consider what fields and methods are needed to represent a class and a generic relationship between two classes.
๐Ÿ’ก Hint
Use an abstract class for UMLRelationship because it holds instance state like source, target, and multiplicity. Interfaces cannot hold state in Java.
abstract class UMLRelationship(source: UMLClass, target: UMLClass, multiplicitySource: Multiplicity, multiplicityTarget: Multiplicity) - abstract because it holds instance state; interface cannot hold fields in Java
Mid: Identifies UMLRelationship as abstract class to hold shared state. Senior: Explains why interface cannot hold instance fields in Java and how abstract class enables shared behavior and state.
โš ๏ธCommon Wrong Answer
Using interface for UMLRelationship leads to inability to hold multiplicity fields, forcing duplication in subclasses and violating DRY.
Step 2
Implement Relationship Types with Enum and Inheritance
How will you represent the four relationship types and their specific drawing styles? Design the class hierarchy or enum usage to support this.
๐Ÿ’ก Hint
Use an enum RelationshipType with constants ASSOCIATION, AGGREGATION, COMPOSITION, INHERITANCE to represent types. Use inheritance for UMLRelationship subclasses to implement drawing behavior.
enum RelationshipType { ASSOCIATION, AGGREGATION, COMPOSITION, INHERITANCE } - enums provide compile-time safety and exhaustive switch support; UMLRelationship subclasses override draw() method for specific styles
Mid: Uses enum for relationship types and subclasses for behavior. Senior: Explains how enum prevents typo bugs and enables exhaustive switch, and how polymorphism enables open-closed principle.
โš ๏ธCommon Wrong Answer
Using String constants for relationship types causes runtime typo bugs and no exhaustive switch checking, leading to drawing errors.
Step 3
Represent Multiplicity with a Dedicated Class
Design how multiplicity (e.g., 1, 0..1, *, 1..*) is represented and validated in the system.
๐Ÿ’ก Hint
Create a final immutable class Multiplicity with min and max fields as integers or special constants. Use validation in constructor to enforce min โ‰ค max or max = -1 for unlimited.
final class Multiplicity { private final int min; private final int max; } - immutable to ensure thread safety and correctness; validation in constructor enforces valid ranges
Mid: Defines Multiplicity class with min/max fields. Senior: Explains immutability for thread safety and validation to prevent invalid multiplicities at runtime.
โš ๏ธCommon Wrong Answer
Using mutable Multiplicity with setters leads to inconsistent multiplicity states in concurrent updates causing incorrect diagram rendering.
Step 4
Ensure Thread-Safe Updates to Diagram Relationships
How will you ensure thread-safe addition and removal of relationships in the UML diagram?
๐Ÿ’ก Hint
Use synchronized methods or locks on the diagram's relationship collection. For example, public synchronized boolean addRelationship(UMLRelationship r) to atomically check and add.
synchronized methods on Diagram class for addRelationship(UMLRelationship r) and removeRelationship(UMLRelationship r) - atomic check-and-set to prevent race conditions in concurrent modifications
Mid: Uses synchronized keyword on add/remove methods. Senior: Traces exact thread interleaving where without synchronization two threads add same relationship causing inconsistent state.
โš ๏ธCommon Wrong Answer
Not synchronizing add/remove methods leads to race conditions where two threads corrupt the relationships collection causing lost updates or exceptions.
Step 5
Design Extensibility for New Relationship Types
How will you design the system to allow adding new relationship types without modifying existing UMLRelationship or Diagram classes?
๐Ÿ’ก Hint
Use the Open-Closed Principle: define UMLRelationship as abstract class with abstract draw() method. New relationship types extend UMLRelationship and override draw(). Use enum for known types but allow custom types via subclassing.
abstract class UMLRelationship with abstract draw(Graphics g) method - subclasses implement drawing; Open-Closed Principle enforced by inheritance and polymorphism
Mid: Uses abstract class and polymorphism for extensibility. Senior: Explains how this avoids modifying existing code and how Java's dynamic dispatch enables new types without recompilation of existing classes.
โš ๏ธCommon Wrong Answer
Using switch-case on enum in Diagram to draw relationships forces modification of Diagram class for new types, violating Open-Closed Principle.
๐Ÿ”Œ
API Design Challenge
Design a Java API that allows clients to create UML classes and relationships with multiplicity, supports drawing with correct UML notation, and enables thread-safe updates. The API should be extensible to add new relationship types without modifying existing code.
  • Use an abstract class UMLRelationship with abstract draw(Graphics g) method to enable polymorphic drawing.
  • Represent multiplicity with an immutable Multiplicity class with validated min and max fields.
  • Synchronize add/remove methods in the Diagram class to ensure thread-safe updates.
๐Ÿ“Š
Scoring Rubric
โ–ผ Show
Must Have - 60%
  • abstract class UMLRelationship with source, target, and multiplicity fields - abstract because interfaces cannot hold instance state in Java
  • enum RelationshipType for ASSOCIATION, AGGREGATION, COMPOSITION, INHERITANCE with compile-time type safety
  • final immutable Multiplicity class with validated min and max fields
  • synchronized addRelationship and removeRelationship methods in Diagram class for thread-safe updates
  • abstract draw(Graphics g) method in UMLRelationship enabling polymorphic drawing per relationship type
Good to Have - 30%
  • Open-Closed Principle enforced via subclassing - new relationship types extend UMLRelationship without modifying existing code
  • Multiplicity validation in constructor preventing invalid ranges (min > max, negative values except -1)
  • Explanation of exact thread interleaving causing race conditions without synchronization
  • Composition vs aggregation lifecycle distinction modeled correctly in UMLRelationship subclasses
  • Diagram class correctly aggregates UMLClass and UMLRelationship with independent vs owned lifecycle
Bonus - 10%
  • Use of ConcurrentHashMap or ReadWriteLock for finer-grained concurrency over synchronized methods
  • Factory pattern for creating UMLRelationship instances by RelationshipType
  • Visitor pattern for rendering different relationship styles without modifying UMLRelationship hierarchy
  • Override of equals and hashCode in Multiplicity for correct set membership and map key usage
Using String constants for relationship types causes runtime typo bugs and no exhaustive switch checking, leading to drawing errors and maintenance issues.
Not synchronizing add/remove methods on Diagram leads to race conditions where concurrent modifications corrupt the relationships collection.
Using mutable Multiplicity objects with setters causes inconsistent multiplicity states in concurrent updates.
Implementing drawing logic with switch-case on enum in Diagram violates Open-Closed Principle when adding new relationship types.
โœ…
Model Answer
โ–ผ Reveal

This system models UML class diagrams focusing on relationships with multiplicity and drawing capabilities. It uses an abstract UMLRelationship class to hold state and enforce polymorphic drawing. Relationship types are represented by an enum for compile-time safety and subclasses for specific drawing behavior. Multiplicity is modeled as an immutable class with validation to ensure correctness. The Diagram class manages UMLClass and UMLRelationship instances with synchronized methods to ensure thread-safe updates. The design follows the Open-Closed Principle allowing new relationship types via subclassing without modifying existing code.

  • Use abstract class UMLRelationship to hold instance state and enable polymorphic drawing, since interfaces cannot hold fields in Java.
  • Represent relationship types with enum RelationshipType for compile-time safety and exhaustive switch support.
  • Implement Multiplicity as a final immutable class with validation in constructor to ensure thread safety and correctness.
  • Synchronize addRelationship and removeRelationship methods in Diagram to prevent race conditions during concurrent updates.
  • Enforce Open-Closed Principle by allowing new relationship types to extend UMLRelationship and override draw(), avoiding modification of existing classes.
  • abstract class UMLRelationship holds source, target UMLClass and multiplicities as instance state; interface cannot hold fields in Java
  • enum RelationshipType provides compile-time safety and exhaustive switch support for relationship types
  • final immutable Multiplicity class with validated min and max fields ensures thread-safe and correct multiplicity representation
  • synchronized methods on Diagram class for addRelationship and removeRelationship ensure atomic updates and prevent race conditions
  • abstract draw(Graphics g) method in UMLRelationship subclasses enables polymorphic drawing behavior per relationship type
  • Open-Closed Principle enforced by abstract class and subclassing allows adding new relationship types without modifying existing code
  • Use of volatile keyword not needed here as synchronization covers visibility and atomicity for relationship collections
  • Composition relationship modeled as UMLRelationship subclass with lifecycle ownership semantics documented
  • Multiplicity validation prevents invalid ranges like min > max or negative values except -1 for unlimited
  • Diagram class aggregates UMLClass and UMLRelationship instances; UMLClass lifecycle independent, UMLRelationship lifecycle tied to Diagram

Practice

(1/5)
1. You want to add a WeekendFeeStrategy to the Restaurant Management System's billing module to apply extra charges on weekends. Given the current design uses a FeeStrategy interface for fees, what is the minimum change required to add this feature while respecting SOLID principles?
medium
A. Add a boolean weekend flag to the Bill class and modify its calculateTotal() method to add fees.
B. Create a new WeekendFeeStrategy class implementing FeeStrategy and inject it where needed without modifying existing classes.
C. Add weekend logic inside the Bill class directly, bypassing FeeStrategy.
D. Modify the existing FeeStrategy implementation to check for weekends and apply extra fees.

Solution

  1. Step 1: Identify the SOLID principle involved

    Open-Closed Principle (OCP) requires adding new behavior without modifying existing code.
  2. Step 2: Evaluate options for minimal change and OCP compliance

    Create a new WeekendFeeStrategy class implementing FeeStrategy and inject it where needed without modifying existing classes. respects OCP by adding a new strategy class without changing existing ones. Add a boolean weekend flag to the Bill class and modify its calculateTotal() method to add fees. modifies Bill class, violating OCP. Modify the existing FeeStrategy implementation to check for weekends and apply extra fees. modifies existing FeeStrategy, violating OCP. Add weekend logic inside the Bill class directly, bypassing FeeStrategy. adds logic in Bill, violating SRP and OCP.
  3. Final Answer:

    Option A -> Option A
  4. Quick Check:

    New FeeStrategy class -> OCP respected [check]
Hint: Add new strategy class -> respect OCP [check]
Common Mistakes:
2. The current Tic-Tac-Toe design uses a WinStrategy interface for win detection. To add a WeekendWinBonusStrategy that applies only on weekends, what is the minimum change required to comply with SOLID principles?
medium
A. Create a new WeekendWinBonusStrategy class implementing WinStrategy and use it without modifying existing classes.
B. Add a boolean flag in the Board class to toggle weekend mode and update all win checks accordingly.
C. Modify the existing WinStrategy implementations to check the day and apply bonus logic.
D. Combine all win detection logic including weekend bonus into a single monolithic class.

Solution

  1. Step 1: Understand OCP and DIP in current design

    Open-Closed Principle (OCP) requires adding new behavior without modifying existing classes. Dependency Inversion Principle (DIP) encourages depending on abstractions.
  2. Step 2: Evaluate options for minimal change

    Create a new WeekendWinBonusStrategy class implementing WinStrategy and use it without modifying existing classes. adds a new strategy class but requires changing client code to use it, violating minimal change. Add a boolean flag in the Board class to toggle weekend mode and update all win checks accordingly. adds a toggle flag in Board, allowing existing strategies to adapt behavior without modifying their code, preserving OCP better than A or D.
  3. Final Answer:

    Option B -> Option B
  4. Quick Check:

    Toggle flag in Board -> minimal change, respects OCP [check]
Hint: OCP: add new class or toggle flag, avoid modifying existing [check]
Common Mistakes:
3. To support ElectricCar and ChargingSpot in the existing parking system using Chain of Responsibility, what is the minimum change that respects extensibility and avoids modifying existing classes?
hard
A. Add ELECTRIC_CAR to VehicleType enum, CHARGING to SpotType enum, create ElectricCar subclass, and update SpotCompatibility.COMPATIBILITY_MAP accordingly.
B. Modify Vehicle and Spot classes to add boolean isElectric and isChargingSpot flags, then update existing handlers to check these flags.
C. Create a new ElectricCarHandler in the chain that handles electric cars and charging spots, modifying the chain setup to include it.
D. Add a new method in Vehicle interface for charging compatibility and implement it in ElectricCar, modifying existing handlers to call it.

Solution

  1. Step 1: Identify extensibility requirements

    Adding ElectricCar and ChargingSpot should not require modifying existing classes to avoid breaking OCP.
  2. Step 2: Evaluate options

    Add ELECTRIC_CAR to VehicleType enum, CHARGING to SpotType enum, create ElectricCar subclass, and update SpotCompatibility.COMPATIBILITY_MAP accordingly. modifies enums and compatibility map, changing existing code; Modify Vehicle and Spot classes to add boolean isElectric and isChargingSpot flags, then update existing handlers to check these flags. adds flags and updates handlers without changing existing class hierarchies; Create a new ElectricCarHandler in the chain that handles electric cars and charging spots, modifying the chain setup to include it. modifies chain setup, which is acceptable but may require modifying chain initialization; Add a new method in Vehicle interface for charging compatibility and implement it in ElectricCar, modifying existing handlers to call it. modifies Vehicle interface, breaking existing implementations.
  3. Step 3: Choose minimal invasive approach

    Modify Vehicle and Spot classes to add boolean isElectric and isChargingSpot flags, then update existing handlers to check these flags. adds minimal changes with flags and updates handlers, avoiding class explosion or interface changes.
  4. Final Answer:

    Option B -> Option B
  5. Quick Check:

    Flags added, existing classes unchanged, handlers updated [check]
Hint: Add flags and update handlers, avoid modifying classes [check]
Common Mistakes:
4. To support ElectricCar jobs requiring ChargingSpot resources in the Job Scheduler, what is the minimum change to the current design to maintain extensibility without modifying existing classes?
hard
A. Create a new GodClass managing both ElectricCar and ChargingSpot logic, bypassing existing abstractions.
B. Add ELECTRIC_CAR to VehicleType enum, CHARGING to SpotType enum, create ElectricCar subclass, and update SpotCompatibility map externally.
C. Modify VehicleType enum to include ElectricCar and add charging logic inside existing Vehicle class.
D. Add charging logic directly inside Job class and modify existing Spot classes to handle ElectricCar.

Solution

  1. Step 1: Identify extensibility requirements

    ElectricCar and ChargingSpot are new types requiring minimal impact on existing Vehicle and Spot classes.
  2. Step 2: Apply extensibility without modifying existing classes

    Add new enum values for types, create ElectricCar subclass, and update SpotCompatibility map externally to maintain OCP and avoid class explosion.
  3. Final Answer:

    Option B -> Option B
  4. Quick Check:

    New enums + subclass + external compatibility update -> minimal existing code change [check]
Hint: Add new enums + subclass + external map update -> minimal change [check]
Common Mistakes:
5. The Workflow Engine must support ElectricCar vehicles requiring ChargingSpot compatibility. What is the minimum change to the current design to add this without modifying existing classes?
hard
A. Add charging logic inside Executor class to handle ElectricCar spots dynamically.
B. Modify Vehicle base class to include isElectric flag and add charging logic inside existing Spot classes.
C. Create a new ElectricVehicle interface and modify all existing Vehicle subclasses to implement it.
D. Add ELECTRIC_CAR to VehicleType enum, CHARGING to SpotType enum, create ElectricCar subclass, and update SpotCompatibility.COMPATIBILITY_MAP accordingly.

Solution

  1. Step 1: Identify extensibility requirements

    Adding ElectricCar and ChargingSpot must not modify existing classes to respect OCP and avoid class explosion.
  2. Step 2: Use enums and subclassing

    Adding new enum values and a new ElectricCar subclass extends functionality cleanly; updating compatibility map centralizes spot-vehicle matching without changing existing code.
  3. Step 3: Avoid modifying base classes or Executor

    Modifying Vehicle or Executor violates OCP and risks introducing bugs.
  4. Final Answer:

    Option D -> Option D
  5. Quick Check:

    New enums + subclass + compatibility map update -> minimal, no existing class change [check]
Hint: Add enums + subclass + map update, no existing class change [check]
Common Mistakes:
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard