Milestone 3: Design pattern - SENG-350-2024-fall/Team-13 GitHub Wiki

Decorator Pattern

General Description:

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.

Manifestation in the System:

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.

Example in Code:

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

UML Diagram:

rec-1

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

Singleton Pattern

General Description:

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.

Manifestation in the System:

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.

Example in Code:

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 Diagram:

rec-2

PlantUML Script
@startuml
class ReceiptManager {
    - static instance: ReceiptManager
    - receipts: { [key: string]: Receipt }
    - constructor()
    + static getInstance(): ReceiptManager
    + generateReceipt(triageData): Receipt
}

ReceiptManager --|> Receipt

ReceiptManager : <<Singleton>>
@enduml

State pattern

General description:

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

Manifestation in the system:

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".


Facade pattern

General description:

  • Simplifies a complex system by providing an easy-to-use, which hides unecessary and complex details.

Manifestation in the system:

  • 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

General description:

  • 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.

Manifestation in the system:

  • Shared elements in dashboard:
    • system can display relevent data related to all users to remove duplicate components.
⚠️ **GitHub.com Fallback** ⚠️