Milestone 3: Design pattern - SENG-350-2024-fall/Team-13 GitHub Wiki
The decorator pattern allows the addition of functionality without modifying the existing structure. By having a base component that represents the core behavior, decorators can add new functionality dynamically, providing a flexible alternative to subclassing for extending behavior.
In our system, the decorator pattern is used to calculate the total cost of a hospital visit. The Receipt
class acts as the base for calculating costs, with different types of expenses (e.g., symptoms assessments, pain level assessments, medical history reviews, severity assessments) dynamically added to the receipt. Each of these items contributes additional costs, effectively "decorating" the base consultation cost. This approach keeps the core structure clean and supports extensibility, allowing us to add or modify cost components without changing the underlying class structure.
The Receipt
class tracks costs by adding ReceiptItem
objects, each representing a component of the total cost. Here’s a breakdown of how additional assessments and fees are dynamically added as decorators to the base cost:
class ReceiptItem {
constructor(public description: string, public cost: number) { }
}
class Receipt {
private items: ReceiptItem[] = [];
private total: number = 0;
addItem(item: ReceiptItem) {
this.items.push(item);
this.total += item.cost;
}
getItems(): ReceiptItem[] {
return this.items;
}
getTotal(): number {
return this.total;
}
}
// Example usage:
const receipt = new Receipt();
receipt.addItem(new ReceiptItem("Base Consultation Fee", 50));
receipt.addItem(new ReceiptItem("Symptom Assessment", 15));
receipt.addItem(new ReceiptItem("Pain Assessment", 10));
console.log(receipt.getTotal()); // Total cost calculated dynamically
PlantUML Script
@startuml
class Receipt {
- items: ReceiptItem[]
- total: number
+ addItem(item: ReceiptItem)
+ getItems(): ReceiptItem[]
+ getTotal(): number
}
class ReceiptItem {
+ description: string
+ cost: number
}
Receipt "1" o-- "*" ReceiptItem : contains
@enduml
The singleton pattern restricts the instantiation of a class to a single object. This ensures that there is only one instance of the class in the system, which can be accessed globally. It is commonly used to manage shared resources, such as a central manager or coordinator.
The ReceiptManager
class is implemented as a singleton, ensuring that there is only one instance managing the receipts and patient consultations across the system. This is achieved through a private constructor and a static getInstance
method, which creates the ReceiptManager
instance only if it doesn’t already exist. By using a singleton for ReceiptManager
, the system avoids duplicate records for receipts and ensures a consistent source for retrieving or updating patient receipt data. This implementation guarantees centralized management of all receipts in the application.
In the code, ReceiptManager.getInstance()
returns a single instance of ReceiptManager
. This approach ensures centralized management of receipt generation and storage.
class ReceiptManager {
private static instance: ReceiptManager;
private receipts: { [key: string]: Receipt } = {};
private constructor() { }
static getInstance(): ReceiptManager {
if (!ReceiptManager.instance) {
ReceiptManager.instance = new ReceiptManager();
}
return ReceiptManager.instance;
}
generateReceipt(triageData): Receipt {
const receipt = new Receipt();
// Generate receipt logic
this.receipts[triageData.id] = receipt;
return receipt;
}
}
// Usage:
const receiptManager1 = ReceiptManager.getInstance();
const receiptManager2 = ReceiptManager.getInstance();
console.log(receiptManager1 === receiptManager2); // true
PlantUML Script
@startuml
class ReceiptManager {
- static instance: ReceiptManager
- receipts: { [key: string]: Receipt }
- constructor()
+ static getInstance(): ReceiptManager
+ generateReceipt(triageData): Receipt
}
ReceiptManager --|> Receipt
ReceiptManager : <<Singleton>>
@enduml
The state pattern involves the different states that the system goes though in various points of time to keep track of what state the system currently is in and which state will come next
The state pattern will first be implemented in our system with log in/log out where one state is logged in and the other is logged out. The user can switch between these two states and the actions that the user can perform in each of these states are different. The state pattern can also be used in our system's virtual triage. For example, "waiting for placement", "high severity", "medium severity" and "low severity".
- Simplifies a complex system by providing an easy-to-use, which hides unecessary and complex details.
- In our system, this pattern controls dashboard views. Patients see only their own status, while doctors see all patient statuses. This ensures each user sees only what’s relevant to them.
- Adapter Pattern's purpose is to convert one class's interface into another interface that clients expect. It enables classes to work with each other who wouldn't be able to due to incompatible interfaces.
- Shared elements in dashboard:
- system can display relevent data related to all users to remove duplicate components.