22 KiB
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
- Matriks Ringkasan
- Builder Pattern
- Singleton Pattern
- Facade Pattern
- Repository / Proxy Pattern
- Observer Pattern
- Strategy Pattern
- 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:
YoloDetectormemuat model.tflite±6 MB ke memori — jika dibuat ulang setiap buka layar akan terjadi memory leak dan delay 2–3 detik.WebSocketServicemempertahankan satu koneksi STOMP ke backend — multiple instance menyebabkan event diterima dobel.TtsServicemengelola engine TTS — dua instance berbicara bersamaan akan saling menimpa.AgoraServicemengelola 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).