🚧 Under Construction – This project is actively being developed. Some features are complete, while others are still in progress. See the Implementation Status section for details.
Java console application that walks through the entire cake-ordering journey—from order placement to pickup—while demonstrating four classic design patterns described in project_description.pdf.
- Implementation Status
- 1. Project Goals
- 2. Required Design Patterns
- 3. Completed Modules
- 4. Pending Modules
- 5. Build & Run Instructions
- 6. JSON Storage Flow
- 7. Definition of Done for MVP
- 8. Next Steps
- 9. Code Quality Notes
- 10. Authors
| Module | Status | Pattern |
|---|---|---|
cakes |
✅ Complete | Base classes |
decorators |
✅ Complete | Decorator Pattern |
factory |
✅ Complete | Factory Pattern |
ordering |
✅ Complete | Singleton Pattern |
observers |
✅ Complete | Observer Pattern |
demo |
✅ Complete | Test runner |
storage |
⏳ Pending | JSON persistence |
- Accept customer orders, build the requested cake, apply optional decorations, and hand off the finished cake for pickup.
- Maintain exactly one connection to the central ordering processor to avoid race conditions or duplicated tickets.
- Keep both the customer-facing dashboard (order number + cake name) and the manager dashboard (running totals per cake type) synchronized in real time.
- Persist orders, customers, and dashboard state in JSON files that load at startup and save when the app exits.
- Factory ✅ – Create
AppleCake,CheeseCake, andChocolateCakeinstances through a dedicated factory so higher layers stay decoupled from concrete classes. - Decorator ✅ – Allow customers to stack chocolate chips, cream, and skittles on any cake using nested decorators without altering the base cake implementation.
- Singleton ✅ – Expose a single
CakeOrderingSysteminstance that routes every order to the central processor. - Observer ✅ – Notify both dashboards each time a cake is finalized so their displays always match the latest production state.
Status: Fully implemented with complete Javadoc documentation.
Files:
cakes/Cake.java– Abstract base class with order ID, base name, size, and base price managementcakes/AppleCake.java– Concrete apple cake implementationcakes/CheeseCake.java– Concrete cheese cake implementationcakes/ChocolateCake.java– Concrete chocolate cake implementation
Features:
- Abstract
Cakeclass withdescribe()andgetCost()methods - Three concrete cake types ready for decoration
- Each cake maintains order ID, size, and base price
- Full Javadoc documentation for all classes and methods
Status: Fully implemented with centralized logic and snapshot pattern.
Files:
decorators/CakeDecorator.java– Abstract decorator base class with centralized grammar and cost logicdecorators/ChocolateChipsDecorator.java– Adds chocolate chips (cost: $2.50)decorators/CreamDecorator.java– Adds cream (cost: $2.00)decorators/SkittlesDecorator.java– Adds skittles (cost: $1.50)
Features:
- ✅ Centralized Grammar Logic – Smart description handling:
- 1st decoration:
"Cake with [Decoration]" - 2nd decoration:
"Cake with X and [Decoration]" - 3rd+ decorations:
"Cake with X, Y, and [Decoration]"(Oxford comma style)
- 1st decoration:
- ✅ Snapshot Pattern – Decoration cost/name captured at construction time
- Existing objects preserve original prices even if static fields change
- New objects use updated prices
- ✅ Composable Decorators – Decorators can be chained together
- ✅ Centralized Cost Calculation – All cost logic in base class
- ✅ Configurable Prices – Static setters/getters for future price changes
Example Usage:
// Single decoration
Cake base = new ChocolateCake(1, "Large", 12.50);
Cake decorated = new CreamDecorator(base);
// Result: "Order #1: Chocolate Cake (Large) with Cream"
// Cost: 12.50 + 2.00 = 14.50
// Multiple decorations
Cake fullyDecorated = new ChocolateChipsDecorator(
new SkittlesDecorator(
new CreamDecorator(base)
)
);
// Result: "Order #1: Chocolate Cake (Large) with Cream, Skittles, and Chocolate Chips"
// Cost: 12.50 + 2.00 + 1.50 + 2.50 = 18.50Status: Fully implemented with automatic order ID generation and pricing management.
Files:
factory/CakeFactory.java– Static factory class for creating cake instances
Features:
- ✅ Static Factory Method –
createCake(CakeType, CakeSize)creates appropriate cake instances - ✅ Automatic Order ID Generation – Format:
APP-L-001,CHE-M-002,CHO-S-003- Type-specific counters maintain independent numbering per cake type
- Format:
[3-letter type code]-[1-letter size code]-[3-digit sequential number]
- ✅ Pricing Table – Embedded pricing data structure with default prices:
- Apple Cake: Small $8.00, Medium $10.00, Large $12.00
- Cheese Cake: Small $10.50, Medium $12.50, Large $15.00
- Chocolate Cake: Small $10.50, Medium $12.50, Large $15.00
- ✅ Price Management – Public methods for querying and updating prices:
getPrice(CakeType, CakeSize)– Query current pricesetBasePrice(CakeType, CakeSize, double)– Update price dynamicallyresetPricesToDefault()– Restore original pricing
- ✅ Type Counter Access –
getCountForType(CakeType)for dashboard statistics - ✅ Full Javadoc Documentation – Complete documentation for all methods
Example Usage:
// Create cakes using factory
Cake appleCake = CakeFactory.createCake(CakeType.APPLE, CakeSize.MEDIUM);
// Order ID: APP-M-001, Price: $10.00
Cake cheeseCake = CakeFactory.createCake(CakeType.CHEESE, CakeSize.LARGE);
// Order ID: CHE-L-001, Price: $15.00
// Query prices
double price = CakeFactory.getPrice(CakeType.CHOCOLATE, CakeSize.SMALL);
// Returns: 10.50
// Get count for manager dashboard
int count = CakeFactory.getCountForType(CakeType.APPLE);
// Returns: number of Apple cakes created (next order number)Status: Fully implemented with thread-safe singleton and observer integration.
Files:
ordering/CakeOrderingSystem.java– Singleton ordering system orchestrating the entire order flow
Features:
- ✅ Singleton Pattern – Thread-safe double-checked locking implementation
- Single instance accessible via
getInstance() - Prevents multiple ordering system instances
- Single instance accessible via
- ✅ Observer Registration – Register/unregister observers for order completion notifications
registerObserver(OrderObserver)– Add observer to notification listremoveObserver(OrderObserver)– Remove observer from notifications
- ✅ Order Placement –
placeOrder()method orchestrates the complete flow:- Creates base cake using
CakeFactory - Applies decorations in sequence using Decorator pattern
- Notifies all registered observers
- Returns fully decorated cake
- Creates base cake using
- ✅ Decoration Application – Maps
Decorationenum to appropriate decorator classes - ✅ Integration – Seamlessly integrates Factory, Decorator, and Observer patterns
- ✅ Full Javadoc Documentation – Complete documentation with usage examples
Example Usage:
// Get singleton instance
CakeOrderingSystem system = CakeOrderingSystem.getInstance();
// Register dashboards
system.registerObserver(new CustomerDashboard());
system.registerObserver(new ManagerDashboard());
// Place an order with decorations
List<Decoration> decorations = Arrays.asList(
Decoration.CREAM,
Decoration.CHOCOLATE_CHIPS
);
Cake order = system.placeOrder(
CakeType.CHOCOLATE,
CakeSize.LARGE,
decorations,
"John Doe"
);
// Automatically creates cake, applies decorations, and notifies observersStatus: Fully implemented with Customer and Manager dashboard observers.
Files:
observers/OrderObserver.java– Observer interface for order completion notificationsobservers/CustomerDashboard.java– Customer-facing dashboard displaying order detailsobservers/ManagerDashboard.java– Manager dashboard displaying cake type statistics
Features:
- ✅ Observer Interface –
OrderObserverdefines the contract for order notificationsupdate(Cake)method receives completed cake objects
- ✅ Customer Dashboard – Displays order number and full cake description
- Format:
"Order #APP-L-001: Apple Cake (Large) with Cream" - Maintains list of all completed orders
- Methods:
getCompletedOrders(),getOrderCount(),clear()
- Format:
- ✅ Manager Dashboard – Displays cake type with current count
- Format:
"Cheese Cake – 123" - Queries
CakeFactoryfor type-specific counts - Shows only the latest sold cake type
- Format:
- ✅ Automatic Updates – Both dashboards receive real-time notifications via Observer pattern
- ✅ Full Javadoc Documentation – Complete documentation for all classes
Example Usage:
// Create dashboards
CustomerDashboard customerView = new CustomerDashboard();
ManagerDashboard managerView = new ManagerDashboard();
// Register with ordering system
CakeOrderingSystem system = CakeOrderingSystem.getInstance();
system.registerObserver(customerView);
system.registerObserver(managerView);
// When an order is placed, both dashboards automatically update:
// Customer Dashboard: "Order #CHO-M-001: Chocolate Cake (Medium) with Cream"
// Manager Dashboard: "Chocolate Cake – 1"Status: Fully implemented with comprehensive end-to-end demonstration.
Files:
demo/CakeShopDemo.java– Complete demonstration of all four design patterns working together
Features:
- ✅ Complete Pattern Integration – Demonstrates all four design patterns:
- Factory Pattern: Cake creation via
CakeFactory - Decorator Pattern: Applying decorations to cakes
- Singleton Pattern: Single
CakeOrderingSysteminstance - Observer Pattern: Customer and Manager dashboards receiving notifications
- Factory Pattern: Cake creation via
- ✅ Multiple Sample Orders – Places 5 diverse orders showcasing:
- Different cake types (Apple, Chocolate, Cheese)
- Different sizes (Small, Medium, Large)
- Various decoration combinations (single, multiple, none)
- ✅ Real-Time Dashboard Updates – Shows both dashboards updating automatically as orders are completed
- ✅ Final Summary – Displays total orders placed
- ✅ Full Javadoc Documentation – Complete documentation explaining the demo
Example Output:
The demo places orders and shows:
- Order processing details (customer name, cake type, size, decorations)
- Customer Dashboard updates (order number + full description)
- Manager Dashboard updates (cake type + count)
- Final summary with total orders
Running the Demo:
# Compile all modules
javac cakes/*.java decorators/*.java factory/*.java ordering/*.java observers/*.java demo/*.java
# Run the demo
java -cp . demo.CakeShopDemostorage– JSON loader/saver utilities responsible for hydrating domain objects at startup and flushing changes on shutdown.
From the project root directory:
# Compile all classes at once (recommended)
javac cakes/*.java decorators/*.java factory/*.java ordering/*.java observers/*.java demo/*.java
# Or compile modules individually
javac cakes/*.java
javac decorators/*.java
javac factory/*.java
javac ordering/*.java
javac observers/*.javaThe project includes a comprehensive demo that demonstrates all four design patterns working together.
Compile all modules:
javac cakes/*.java decorators/*.java factory/*.java ordering/*.java observers/*.java demo/*.javaRun the demo:
java -cp . demo.CakeShopDemoThe demo will:
- Place 5 sample orders with different cake types, sizes, and decorations
- Show real-time updates on both Customer and Manager dashboards
- Display order processing details for each order
- Show a final summary with total orders placed
This demonstrates all four design patterns:
- Factory Pattern: Creating cakes with auto-generated order IDs
- Decorator Pattern: Applying multiple decorations in sequence
- Singleton Pattern: Ensuring a single ordering system instance
- Observer Pattern: Updating both dashboards automatically
- On program start, load JSON files (orders, customers, dashboard stats) into memory so the system resumes prior state automatically.
- During runtime, all modifications go through domain services while keeping in-memory state authoritative.
- On graceful shutdown, serialize the latest state back to the same JSON files to persist progress.
| Requirement | Status |
|---|---|
| ✅ Decorator pattern fully implemented | Complete |
| ✅ All three cake types implemented | Complete |
| ✅ Factory pattern implemented | Complete |
| ✅ Singleton ordering system | Complete |
| ✅ Observer dashboards | Complete |
| ✅ End-to-end demo | Complete |
| ✅ Complete Javadoc documentation | Complete |
| ⏳ JSON persistence | Pending |
- ✅ Decorator Pattern – DONE! All decorators implemented with centralized logic
- ✅ Factory Pattern – DONE! Factory creates cakes with auto-generated order IDs
- ✅ Singleton Pattern – DONE! Thread-safe singleton ordering system implemented
- ✅ Observer Pattern – DONE! Customer and Manager dashboards react to completed orders
- ⏳ JSON Persistence – Wire up JSON storage helpers for data persistence
- Load orders, customers, and dashboard state at startup
- Save state on graceful shutdown
- Javadoc: All public classes and methods fully documented across all modules
- Code Structure: Clean package organization (
cakes,decorators,factory,ordering,observers) - Pattern Implementation: All four design patterns correctly implemented:
- Factory Pattern: Centralized cake creation with automatic ID generation
- Decorator Pattern: Composable decorations with centralized grammar logic
- Singleton Pattern: Thread-safe singleton with double-checked locking
- Observer Pattern: Real-time dashboard updates via observer notifications
- Supporting Enums: Type-safe enums for
CakeType,CakeSize, andDecoration - Naming Conventions: PascalCase for classes, camelCase for methods/fields
- Decorator classes: Add constraints to setter methods (validation)
- Size constraints: Add validation for cake sizes
- JSON storage: Implement persistence layer for orders and dashboard state
- Amer Abuyaqob
- Mustafa Abu Saffaqa
- Ahmad Badran
Last Updated: Current implementation covers all four required design patterns (Factory, Decorator, Singleton, Observer) with comprehensive Javadoc documentation and a complete end-to-end demo. JSON persistence is the only remaining task.