Skip to main content

Design Pattern Application

Table of Contents

  1. Introduction
  2. Project Structure
  3. Core Components
  4. Architecture Overview
  5. Detailed Component Analysis
  6. Dependency Analysis
  7. Performance Considerations
  8. Troubleshooting Guide
  9. Conclusion
  10. Appendix

Introduction

This document systematically organizes the application and implementation practices of design patterns in the Sparrow framework, focusing on the following patterns and scenarios:

  • Factory Pattern: Application in service creation and task scheduler instantiation
  • Repository Pattern: Separation of abstraction and implementation in data access layer
  • Observer Pattern: Publish/subscribe and asynchronous processing in event bus
  • Strategy Pattern: Selection and switching of task execution strategies in hybrid scheduler

We will combine code path location, class diagrams and sequence diagrams to explain the problems solved by each pattern, the benefits brought, implementation details and extension methods, helping developers deeply understand and efficiently reuse.

Project Structure

Sparrow adopts an organization approach layered by domain and responsibility:

  • bootstrap: Application bootstrap, container, configuration and startup process
  • usecase: Use case layer interfaces and generic abstractions (repository, session, events, etc.)
  • persistence/repo: Multiple persistence implementations (PostgreSQL, memory, Badger, etc.)
  • eventbus: Event bus abstraction and memory implementation
  • tasks: Task scheduling system (interface, concurrent/sequential/hybrid schedulers, wrapper)
  • messaging: Message bus and stream processing (complementary to event bus)
  • entity: Domain model base classes for aggregates, events, sessions, etc.
  • logger, config, utils and other infrastructure modules

Core Components

  • Container and Factory: Implements "constructor factory" through registration functions and reflection, supports anonymous/named dependency resolution and singleton caching
  • Task Scheduler: Unified interface abstracts concurrent/sequential/hybrid three execution strategies, wrapper responsible for configuration and task building
  • Event Bus: Publish/subscribe model, memory implementation supports asynchronous processing and timeout control
  • Repository: Generic base class provides unified CRUD and query capabilities, concrete database implementations extend as needed

Architecture Overview

Sparrow's runtime is guided by App, injecting various subsystems (task scheduling, event bus, data access) through Container, and exposing task submission and strategy configuration capabilities uniformly through SchedulerWrapper.

Detailed Component Analysis

Factory Pattern: Service Creation and Task Scheduler Instantiation

Container Registration and Resolution:

  • Register "constructor functions" through Register/RegisterNamed, use reflection to infer return type as key
  • Resolve supports named/anonymous resolution, automatically injects dependencies and caches singleton instances
  • Suitable for cross-module decoupling and test double replacement

Task Scheduler Factory:

  • NewConcurrentScheduler/NewSequentialScheduler/NewHybridScheduler as concrete factories
  • SchedulerWrapper.WithConcurrent/WithSequential provides configurable factory extension

Applicable Scenarios:

  • Need to dynamically switch implementations based on environment/configuration (such as different databases, different event buses)
  • Need to centrally manage lifecycle and dependency injection

Repository Pattern: Data Access Layer Abstraction

Abstraction Layer:

  • BaseRepository[T] provides unified CRUD and query interfaces, constrains implementations to complete concrete database adaptation

Concrete Implementation:

  • PostgresRepository[T] based on sqlx implementation, encapsulates transactions, batch operations, conditional queries, soft delete, etc.

Advantages:

  • Decouples business use cases from data sources, convenient for replacing/extending storage backends
  • Generic constraints on entity types, improves compile-time safety

Observer Pattern: Event Bus Publish/Subscribe

Memory Event Bus:

  • Pub/Sub/Unsub/Close provides publish/subscribe/unsubscribe/close capabilities
  • Asynchronously calls subscription handlers, built-in timeout control, avoids blocking publisher

Applicable Scenarios:

  • Domain event decoupling, cross-module notification, observability metric collection

Strategy Pattern: Task Scheduling Strategy Selection

Strategy Interface:

  • TaskScheduler abstracts unified scheduling behavior

Strategy Implementations:

  • concurrentScheduler: Concurrent execution, supports maximum concurrency, TTL, retry and expiration cleanup
  • sequentialScheduler: Sequential execution, strict serialization, suitable for scheduled/periodic tasks
  • HybridScheduler: Chooses strategy based on task type and scheduling time, supports configuration mapping

Wrapper:

  • SchedulerWrapper responsible for task building, retry strategy, concurrency and mode mapping configuration

Dependency Analysis

Container and Application

  • App injects logging, routing, NATS connection, event publisher, session service, etc. through Container
  • Supports named/anonymous resolution and singleton caching, reduces global state coupling

Scheduler Composition

  • HybridScheduler composes concurrent/sequential schedulers, chooses strategy by task type and scheduling time
  • SchedulerWrapper unified configuration entry, simplifies external calls

Event Bus and Task Scheduling

  • Both event bus and task scheduler implement Start/Stop/Close interfaces, convenient for unified lifecycle management

Performance Considerations

Container Resolution

  • Optimizes repeated resolution cost through singleton caching and named/anonymous resolution

Task Scheduling

  • Concurrent scheduler uses polling + timeout control to avoid starvation; sequential scheduler reduces contention through queue and notification channels
  • TTL and expiration cleanup prevent memory bloat

Event Bus

  • Asynchronous processing and timeout control avoid blocking publisher; subscriber statistics facilitate capacity assessment

Troubleshooting Guide

Container Resolution Failure

  • Symptom: Resolve returns "provider not found" or "output not pointer"
  • Troubleshooting: Confirm Register/RegisterNamed constructor signature and return type match; ensure Resolve's out is non-null pointer

Task Scheduling Abnormal

  • Symptom: Task status is failed/cancelled/dead letter
  • Troubleshooting: View retry count and NextRetryAt; check task timeout and cancellation callback; verify scheduler mode configuration

Event Bus Blocking

  • Symptom: Pub blocks or handler doesn't return for a long time
  • Troubleshooting: Check handler timeout settings and implementation; confirm bus not closed; monitor subscriber count and processing duration

Conclusion

Sparrow achieves service decoupling, data access abstraction, event decoupling and flexible scheduling strategy switching through design patterns such as factory, repository, observer and strategy. Container and wrapper further reduce integration complexity, making extension and testing more convenient. It is recommended to follow existing interface and pattern conventions when adding new modules, prioritize using factory and wrapper for assembly, ensure system consistency and maintainability.

Appendix

Code Example Paths (for locating implementations)

Container Registration and Resolution:

Task Scheduler Interface and Implementations:

Event Bus:

Repository:

Application Bootstrap and Assembly: