22 KiB
Raw Permalink Blame History

Mapping Class per Design Pattern — WalkGuide

Dokumen ini memetakan setiap class dari Class Diagram WalkGuide ke design pattern yang menggunakannya, beserta peran class tersebut dalam pattern dan justifikasi pemilihannya.


Daftar Isi

  1. Matriks Ringkasan
  2. Builder Pattern
  3. Singleton Pattern
  4. Facade Pattern
  5. Repository / Proxy Pattern
  6. Observer Pattern
  7. Strategy Pattern
  8. Chain of Responsibility Pattern

1. Matriks Ringkasan

Pattern Kategori Class Utama (dari Class Diagram)
Builder Creational User, AuthService, FcmService, AuthDataResponse
Singleton Creational TtsService, SttService, YoloDetector, WebSocketService, AgoraService, HapticService
Facade Structural VoiceCommandHandler, GuardianDashboardService, GuardianController, VoiceCommandConfig
Repository (Proxy) Structural WalkGuideRepositoryImpl, ActivityLogRepositoryImpl, LocationRepositoryImpl, ObstacleLogRepository, ActivityLogRepository
Observer Behavioral WalkGuideBloc, SosBloc, WebSocketService, LocationBroadcaster, GuardianNotificationRepository
Strategy Behavioral ObstacleAnalyzer, AiConfig, AiConfigService, TtsService, HapticService
Chain of Responsibility Behavioral ApiClient, AuthInterceptor, ErrorInterceptor, JwtAuthFilter, SecurityConfig, JwtUtil, CustomUserDetailsService

2. Builder Pattern — Creational

Justifikasi

Entitas User memiliki 8 field — tidak semua selalu terisi. Field uniqueUserId hanya ada untuk ROLE_USER, fcmToken di-update setiap login, dan displayName bersifat opsional. Tanpa Builder, constructor membutuhkan 8 parameter yang rawan salah urutan dan sulit dibaca. FcmService membangun payload Firebase Message secara kondisional (beberapa field hanya ada saat SOS, yang lain hanya saat notifikasi biasa) — Builder sangat cocok untuk kasus ini.

Class yang Terlibat

Class Layer Peran dalam Pattern Lokasi di Class Diagram
User Backend — Entity Product — objek yang dibangun step-by-step via @Builder Lombok Entity block
AuthService Backend — Service Director/Client — memanggil User.builder()...build() saat register Service block
FcmService Backend — Service Client — memanggil Message.builder() Firebase untuk bangun payload FCM Service block
AuthDataResponse Backend — DTO Product 2 — response token dibangun via AuthDataResponse.builder() DTO block
RefreshToken Backend — Entity Product 3 — dibuat via builder saat generate refresh token Entity block

Relasi Antar Class

AuthService ──uses──► User.builder()
                          .email()
                          .password()
                          .displayName()
                          .uniqueUserId()
                          .role()
                          .build()
                              │
                              ▼
                           User (Entity tersimpan ke UserRepository)

FcmService ──uses──► Message.builder()
                          .setToken()
                          .setNotification()
                          .putData("type", "SOS_ALERT")
                          .setAndroidConfig()
                          .build()
                              │
                              ▼
                       FirebaseMessage (dikirim via FCM)

3. Singleton Pattern — Creational

Justifikasi

WalkGuide memiliki beberapa resource-heavy services yang harus ada tepat satu instance:

  • YoloDetector memuat model .tflite ±6 MB ke memori — jika dibuat ulang setiap buka layar akan terjadi memory leak dan delay 23 detik.
  • WebSocketService mempertahankan satu koneksi STOMP ke backend — multiple instance menyebabkan event diterima dobel.
  • TtsService mengelola engine TTS — dua instance berbicara bersamaan akan saling menimpa.
  • AgoraService mengelola RTC engine — satu per sesi, tidak boleh duplikat.

Semua di-register via GetIt service locator sebagai singleton agar seluruh widget tree mendapat instance yang sama.

Class yang Terlibat

Class Layer Peran dalam Pattern Lokasi di Class Diagram
TtsService Flutter — Service Singleton — satu TTS engine untuk seluruh app Services block
SttService Flutter — Service Singleton — satu STT listener always-on Services block
YoloDetector Flutter — AI Singleton — satu model inference engine (6 MB) AI block
WebSocketService Flutter — Service Singleton — satu koneksi STOMP ke backend Services block
AgoraService Flutter — Service Singleton — satu RTC engine untuk VoIP call Services block
HapticService Flutter — Service Singleton — satu haptic controller Services block
GetIt (injection_container) Flutter — DI ServiceLocator — mengelola lifecycle semua singleton Bootstrap

Relasi Antar Class

injection_container.dart
        │
        ├─ sl.registerSingleton<TtsService>(TtsService())
        ├─ sl.registerSingleton<SttService>(SttService())
        ├─ sl.registerSingleton<YoloDetector>(YoloDetector())
        ├─ sl.registerSingleton<WebSocketService>(WebSocketService())
        ├─ sl.registerSingleton<AgoraService>(AgoraService())
        └─ sl.registerSingleton<HapticService>(HapticService())

WalkGuideBloc ──sl<YoloDetector>()──► YoloDetector (instance sama)
WalkGuideBloc ──sl<TtsService>()───► TtsService   (instance sama)
VoiceCommandHandler ──sl<TtsService>()──► TtsService (instance sama, bukan baru)

4. Facade Pattern — Structural

Justifikasi

Memproses satu perintah suara "Send SOS" membutuhkan koordinasi: SttService, command matcher, SosBloc, GPS, TtsService feedback, dan GoRouter navigasi — 6 subsystem berbeda. Tanpa Facade, setiap Widget harus inject dan tahu semua 6 dependency tersebut. VoiceCommandHandler menyederhanakan ini menjadi satu panggilan processText(string).

Di backend, GuardianController membutuhkan data dari 5 repository berbeda untuk render dashboard Guardian. GuardianDashboardService menjadi Facade yang mengagregasi semuanya, sehingga controller cukup memanggil satu method.

Class yang Terlibat

Class Layer Peran dalam Pattern Lokasi di Class Diagram
VoiceCommandHandler Flutter — Service Facade — menyembunyikan koordinasi 6 subsystem voice Services block
WalkGuideBloc Flutter — BLoC Client — hanya tahu processText(), tidak tahu subsystem BLoC block
TtsService Flutter — Service Subsystem — salah satu dari yang dikoordinasikan Services block
SttService Flutter — Service Subsystem — salah satu dari yang dikoordinasikan Services block
VoiceCommandConfig Backend — Entity Data — konfigurasi perintah suara yang dibaca Facade Entity block
VoiceCommandKey Backend — Enum Enum — key identifier 14 perintah suara Enum block
GuardianDashboardService Backend — Service Facade — mengagregasi data dari 5 repository Service block
GuardianController Backend — Controller Client — cukup panggil getGuardianHomeData() Controller block
LocationHistoryRepository Backend — Repository Subsystem — data lokasi terakhir User Repository block
SosEventRepository Backend — Repository Subsystem — data SOS aktif User Repository block
ActivityLogRepository Backend — Repository Subsystem — log aktivitas User Repository block
GuardianNotificationRepository Backend — Repository Subsystem — jumlah notif belum dibaca Repository block
PairingRelationRepository Backend — Repository Subsystem — ambil userId yang dipasangkan ke Guardian Repository block

Relasi Antar Class

Widget ──processText("send sos")──► VoiceCommandHandler (Facade)
                                          │
                          ┌───────────────┼───────────────┐
                          ▼               ▼               ▼
                      SttService      SosBloc         TtsService
                      (stop listen) (TriggerSos)  (speak feedback)

GuardianController ──getGuardianHomeData()──► GuardianDashboardService (Facade)
                                                      │
                              ┌───────────────────────┼───────────────────────┐
                              ▼                       ▼                       ▼
                   LocationHistoryRepo        SosEventRepo          ActivityLogRepo
                   (last location)           (active SOS)          (recent activity)

5. Repository / Proxy Pattern — Structural

Justifikasi

WalkGuide harus berjalan offline-first — tunanetra sering berada di area tanpa sinyal. Log obstacle, activity log, dan update lokasi harus tetap tersimpan lokal (SQLite/Drift) saat offline, kemudian di-sync ke backend saat koneksi kembali. WalkGuideBloc tidak boleh tahu apakah data berasal dari API atau SQLite — keputusan ini ada di Repository Implementation yang bertindak sebagai Proxy.

Class yang Terlibat

Class Layer Peran dalam Pattern Lokasi di Class Diagram
WalkGuideRepository (interface) Flutter — Domain Subject Interface — kontrak yang dipakai BLoC Domain layer
WalkGuideRepositoryImpl Flutter — Data Proxy — memutuskan API vs SQLite Data layer
ActivityLogRepository (interface) Flutter — Domain Subject Interface Domain layer
ActivityLogRepositoryImpl Flutter — Data Proxy Data layer
ObstacleLogRepository Backend — Repository Real Subject — JPA repository backend Repository block
ActivityLogRepository (JPA) Backend — Repository Real Subject — JPA repository backend Repository block
LocationHistoryRepository Backend — Repository Real Subject — JPA repository backend Repository block
ObstacleLog Backend — Entity Data — entitas yang disimpan/diambil Entity block
ActivityLog Backend — Entity Data — entitas yang disimpan/diambil Entity block
LocationHistory Backend — Entity Data — riwayat lokasi User Entity block

Relasi Antar Class

WalkGuideBloc
    │
    │ depends on interface only
    ▼
WalkGuideRepository (interface)
    │ implements
    ▼
WalkGuideRepositoryImpl (Proxy)
    │
    ├─ if (isOnline) ──► REST API  ──► ObstacleLogRepository (JPA)
    │                                       │
    │                                       ▼
    │                                  ObstacleLog (Entity)
    │
    └─ else ────────► SQLite/Drift ──► Local cache
                      (Drift ORM)

6. Observer Pattern — Behavioral

Justifikasi

Saat YOLO mendeteksi obstacle, puluhan komponen perlu bereaksi: overlay bounding box, TTS feedback, haptic, backend log, dan debug panel. Menghubungkan semua ini secara langsung akan menciptakan tight coupling. BLoC pattern adalah implementasi Observer murni — WalkGuideBloc sebagai Subject, widget sebagai Observer. Ketika state baru di-emit, semua subscriber otomatis bereaksi tanpa BLoC perlu tahu siapa saja Observer-nya.

Untuk Guardian, WebSocketService adalah Observer terhadap backend STOMP — Guardian menerima update lokasi User real-time tanpa polling.

Class yang Terlibat

Class Layer Peran dalam Pattern Lokasi di Class Diagram
WalkGuideBloc Flutter — BLoC Concrete Subject — emit state saat obstacle terdeteksi BLoC block
SosBloc Flutter — BLoC Concrete Subject — emit state saat SOS triggered BLoC block
BlocBuilder (widget) Flutter — UI Observer — rebuild UI saat state berubah Widget layer
BlocListener (widget) Flutter — UI Observer — side effects tanpa rebuild UI Widget layer
WebSocketService Flutter — Service Subject — Stream lokasi, SOS, notifikasi Services block
LocationBroadcaster Backend — Component Publisher — push event ke STOMP topics Backend block
GuardianNotificationRepository Backend — Repository Data Store — notifikasi yang perlu di-broadcast Repository block
SosEventRepository Backend — Repository Data Store — SOS event yang di-broadcast ke Guardian Repository block
ActivityLogService Backend — Service Publisher — broadcast activity log via LocationBroadcaster Service block

Relasi Antar Class

YoloDetector ──detect()──► DetectionResult
                                │
                          WalkGuideBloc (Subject)
                          emit(ObstacleDetected)
                                │
                ┌───────────────┼───────────────┐
                ▼               ▼               ▼
          BlocBuilder      BlocListener    BlocConsumer
          (UI rebuild)    (side effects)    (both)
          overlay bbox    SnackBar error   combined

Backend STOMP push:
LocationBroadcaster ──/topic/location/{userId}──► WebSocketService (Subject)
                                                         │
                                           ┌─────────────┼─────────────┐
                                           ▼             ▼             ▼
                                    GuardianMap    GuardianDash   NotifScreen
                                    (live marker)   (SOS alert)  (new notif)

7. Strategy Pattern — Behavioral

Justifikasi

Guardian perlu mengkonfigurasi cara WalkGuide memperingatkan User tentang obstacle. Ada tiga mode: TTS saja (cocok untuk lingkungan tenang), TTS + haptic (default untuk sebagian besar situasi), haptic saja (lingkungan bising seperti pasar atau stasiun). Logika ini bisa berubah kapan saja dari dashboard Guardian tanpa restart app. Strategy Pattern memungkinkan penggantian algoritma alert di runtime tanpa mengubah ObstacleAnalyzer sedikit pun.

Class yang Terlibat

Class Layer Peran dalam Pattern Lokasi di Class Diagram
ObstacleAlertStrategy (interface) Flutter — AI Strategy Interface — kontrak alert(result) Domain/AI layer
TtsOnlyStrategy Flutter — AI Concrete Strategy 1 — hanya TTS Strategy layer
TtsWithHapticStrategy Flutter — AI Concrete Strategy 2 — TTS + haptic Strategy layer
HapticOnlyStrategy Flutter — AI Concrete Strategy 3 — hanya haptic Strategy layer
ObstacleAnalyzer Flutter — AI Context — menyimpan dan mendelegasikan ke strategy AI block
AiConfig Backend — Entity Config Source — menyimpan alertMode yang dipilih Guardian Entity block
AiConfigService Backend — Service Config Manager — update config dan kirim FCM ke User Service block
AiConfigRepository Backend — Repository Persistence — simpan/ambil konfigurasi AI Repository block
TtsService Flutter — Service Subsystem — dipakai oleh TtsOnly dan TtsWithHaptic Services block
HapticService Flutter — Service Subsystem — dipakai oleh TtsWithHaptic dan HapticOnly Services block
FcmService Backend — Service Notifier — kirim FCM ke User saat config berubah Service block

Relasi Antar Class

Guardian PUT /guardian/ai-config
    │
    ▼
AiConfigService ──updateConfig()──► AiConfig (simpan alertMode)
    │
    └──► FcmService.sendToUser() ──► FCM ke User: "ai_config_updated"
                                              │
                                    Flutter terima FCM
                                              │
                                    switch (config.alertMode)
                                    ┌─────────┼──────────┐
                                    ▼         ▼          ▼
                               TtsOnly  TtsHaptic  HapticOnly
                               Strategy  Strategy   Strategy
                                    │
                          ObstacleAnalyzer.setStrategy(new)
                                    │
                          _strategy.alert(detectionResult)

8. Chain of Responsibility Pattern — Behavioral

Justifikasi

Setiap HTTP request dari Flutter perlu melewati beberapa proses berurutan: (1) menambahkan JWT, (2) auto-refresh jika expired, (3) error mapping terpusat, (4) logging. Tanpa Chain of Responsibility, setiap Repository harus menulis ulang logika ini. Di backend, setiap request perlu (1) divalidasi JWT, (2) dicek role-nya sebelum mencapai controller bisnis. Chain memungkinkan setiap handler fokus pada tanggung jawabnya sendiri dan meneruskan ke handler berikutnya.

Class yang Terlibat

Class Layer Peran dalam Pattern Lokasi di Class Diagram
Interceptor (abstract Dio) Flutter — Network Abstract Handler Network layer
AuthInterceptor Flutter — Network Concrete Handler 1 — inject token, auto-refresh Network layer
ErrorInterceptor Flutter — Network Concrete Handler 2 — map HTTP error ke Failure Network layer
LogInterceptor Flutter — Network Concrete Handler 3 — logging request/response Network layer
ApiClient Flutter — Network Chain Builder — mengatur urutan dan membangun chain Network layer
OncePerRequestFilter (Spring) Backend — Security Abstract Handler Security block
JwtAuthFilter Backend — Security Concrete Handler 1 — validasi JWT, set SecurityContext Security block
SecurityConfig Backend — Security Concrete Handler 2 — RBAC routing per URL pattern Security block
JwtUtil Backend — Security Component — dipakai JwtAuthFilter untuk decode/validate Security block
CustomUserDetailsService Backend — Security Component — dipakai JwtAuthFilter untuk load user dari DB Security block
UserRepository Backend — Repository Data Source — dipakai CustomUserDetailsService Repository block
GlobalExceptionHandler Backend — Exception Error Handler — menangkap exception dari seluruh chain Exception block

Relasi Antar Class

Flutter HTTP Request
    │
    ▼
[Chain[0]] AuthInterceptor ──onRequest()──► inject "Bearer {token}" ──► next()
    │
    ▼
[Chain[1]] ErrorInterceptor ──onRequest()──► pass-through ──► next()
    │
    ▼
[Chain[2]] LogInterceptor ──onRequest()──► log URL + body ──► next()
    │
    ▼  (HTTP over network)
    │
[Backend] JwtAuthFilter ──doFilterInternal()──► validate JWT ──► chain.doFilter()
    │
    ▼
[Backend] SecurityConfig ──securityFilterChain()──► cek role ──► pass
    │
    ▼
[Backend] Controller ──handleRequest()──► proses bisnis
    │
    ▼
[Backend] GlobalExceptionHandler ──► tangkap exception jika ada
    │
    ▼  (HTTP Response)
    │
[Chain[2]] LogInterceptor.onResponse() ──► log response
    │
    ▼
[Chain[1]] ErrorInterceptor.onResponse() ──► map error jika 4xx/5xx
    │
    ▼
[Chain[0]] AuthInterceptor.onError() ──► jika 401: refresh token + retry
    │
    ▼
Repository / BLoC menerima Either<Failure, Data>

Ringkasan Jumlah Class per Pattern

Pattern Jumlah Class Terlibat Layer
Builder 5 class Backend
Singleton 7 class Flutter
Facade 13 class Flutter + Backend
Repository/Proxy 10 class Flutter + Backend
Observer 9 class Flutter + Backend
Strategy 11 class Flutter + Backend
Chain of Responsibility 12 class Flutter + Backend
Total unik ±40 class Full Stack

Semua class di atas dapat ditelusuri langsung di Class Diagram WalkGuide (file PDF yang dilampirkan).