Skip to content

Latest commit

 

History

History

README.md

MVC Pattern: DJ BeatBox & Heart Monitor Examples

Two Swing-based applications demonstrating the Model-View-Controller (MVC) architectural pattern combined with the Observer and Adapter patterns.

Overview

This package contains two MVC applications:

  1. DJ BeatBox - A MIDI-based beat machine that plays drum beats, displays the current BPM and a visual beat indicator, and lets the user control playback via a menu and BPM adjustment buttons.

  2. Heart Monitor - A heart rate monitoring simulator that uses the same UI infrastructure as the DJ BeatBox but adapts a simple heart model to work with the existing view. Demonstrates the Adapter pattern.

Design Patterns Used

1. Model-View-Controller (MVC)

The core architectural pattern, splitting the application into three distinct roles:

Role Class Responsibility
Model BeatModel Manages MIDI sequencer state and BPM; notifies observers of changes
View DJView Renders the UI; reads state from the model; sends user actions to controller
Controller BeatController Responds to user input; translates it into model operations; updates view state

Flow:

User Input → Controller → Model (state change)
                                ↓
                        Observer notification
                                ↓
                           View updates

The controller holds references to both the model and the view. The view holds a reference to both the model (to read state) and the controller (to forward user actions). The model knows nothing about the view or controller — it only notifies registered observers.

2. Observer Pattern

Used to decouple the model from the view. There are two separate observer channels:

  • BeatObserver — notified on every beat tick (fires updateBeat())
  • BPMObserver — notified whenever the BPM value changes (fires updateBPM())

DJView implements both interfaces and registers itself with the model at construction time. BeatBar also implements BeatObserver to animate the progress bar independently.

Structure:

BeatModelInterface
├── registerObserver(BeatObserver)
├── registerObserver(BPMObserver)
├── removeObserver(BeatObserver)
└── removeObserver(BPMObserver)

BeatModel (subject)
├── notifies BeatObservers  →  DJView.updateBeat(), BeatBar.updateBeat()
└── notifies BPMObservers   →  DJView.updateBPM()

3. Adapter Pattern

The HeartAdapter class demonstrates the Adapter pattern by wrapping the HeartModel (which has a different interface) to make it compatible with BeatModelInterface. This allows the heart monitoring system to reuse the existing DJView without modification.

Structure:

HeartModel (incompatible interface)
    ↓
HeartAdapter (adapts to BeatModelInterface)
    ↓
HeartController → DJView (works with BeatModelInterface)

Key adaptations:

  • HeartModel.getHeartRate()BeatModelInterface.getBPM()
  • HeartModel.setHeartRate()BeatModelInterface.setBPM()
  • Timer-based heartbeat simulation instead of MIDI sequencer

4. Strategy Pattern (implicit)

Controllers program to the BeatModelInterface and ControllerInterface abstractions rather than concrete classes. Different model or controller implementations can be swapped in without changing the view or test drive.

Class Structure

DJ BeatBox Class Diagram

DJTestDrive                   Entry point
│
├── BeatModelInterface        Model contract
│   └── BeatModel             MIDI sequencer, observer lists, BPM state
│
├── ControllerInterface       Controller contract
│   └── BeatController        Wires model and view; handles start/stop/BPM
│
├── DJView                    Swing UI (view + observer)
│   └── BeatBar               Animated JProgressBar (beat observer)
│
├── BeatObserver              Observer interface — beat ticks
└── BPMObserver               Observer interface — BPM changes

Heart Monitor Class Diagram

HeartTestDrive                Entry point
│
├── HeartModel                Timer-based heart rate simulation
│   └── HeartAdapter          Adapts HeartModel to BeatModelInterface
│
├── ControllerInterface       Controller contract
│   └── HeartController       Wires adapter and view; handles start/stop/heart rate
│
└── DJView (reused)           Same Swing UI as DJ BeatBox

How to Compile

From the root of the project:

javac -d out MVCPattern/DJExample/*.java

How to Run

DJ BeatBox Application

java -cp out MVCPattern.DJExample.DJTestDrive

Two windows will open:

  • My BeatBox — displays current BPM label and the animated beat bar, with a "DJ Control" menu containing Start/Stop items
  • DJ Control — BPM input field and + / Set / - buttons

Using the DJ BeatBox:

  1. Select DJ Control → Start from the menu bar to begin playback at 90 BPM
  2. Use the + and - buttons to nudge the BPM up or down by 1
  3. Type a value into the text field and press Set to jump to a specific BPM
  4. Select DJ Control → Stop to stop playback
  5. Close either window to exit

Heart Monitor Application

java MVCPattern.DJExample.HeartTestDrive

Two windows will open (identical UI to DJ BeatBox):

  • My BeatBox — displays current heart rate and the animated beat bar
  • DJ Control — Heart rate input field and + / Set / - buttons

Using the Heart Monitor:

  1. Select DJ Control → Start from the menu bar to begin heartbeat simulation at 72 BPM (default heart rate)
  2. Use the + and - buttons to adjust heart rate by 1
  3. Type a value into the text field and press Set to jump to a specific heart rate
  4. The beat bar flashes with each heartbeat based on the current heart rate
  5. Select DJ Control → Stop to halt the heartbeat simulation
  6. Close either window to exit

Pros and Cons

MVC Pattern

Pros:

  • Clear separation of concerns — UI, business logic, and coordination are independent
  • The model can be tested without a UI
  • The view can be redesigned without touching the model
  • Multiple views of the same model are straightforward to add

Cons:

  • More classes and indirection than a simple single-class UI
  • The view still holds a reference to the model for direct state reads, which creates some coupling
  • For very simple UIs the overhead of three layers may not be worth it

Observer Pattern

Pros:

  • The model has zero knowledge of its views — fully decoupled
  • Multiple independent observers can react to the same event
  • Observers can be added or removed at runtime

Cons:

  • Observers are notified in an unspecified order
  • If an observer is not removed when no longer needed it will be held in memory (potential leak)
  • Cascading or unexpected update chains can be hard to debug

Adapter Pattern

Pros:

  • Allows incompatible interfaces to work together without modifying existing code
  • Enables reuse of existing components (e.g., DJView works with both BeatModel and HeartModel)
  • Follows the Open/Closed Principle — open for extension, closed for modification

Cons:

  • Adds an extra layer of indirection
  • Can make the code harder to understand if overused
  • Performance overhead from delegation (though typically negligible)

Key Takeaways

  • MVC separates what the data is (Model) from how it looks (View) and what the user can do (Controller)
  • Observer pattern is the mechanism that keeps the View in sync with the Model without the Model knowing anything about the View
  • Adapter pattern enables incompatible interfaces to work together, as demonstrated by HeartAdapter making HeartModel compatible with BeatModelInterface
  • Programming to interfaces (BeatModelInterface, ControllerInterface) makes each layer replaceable independently
  • Pattern synergy - combining MVC + Observer + Adapter allows maximum code reuse (same view works with both MIDI beats and heart simulation)