Sobes.tech
Middle

Czy znasz wzorzec projektowy Facade? Opowiedz o swoim doświadczeniu z jego używaniem.

sobes.tech AI

Odpowiedź od AI

Tak, znam wzorzec projektowy Facade. Jest to wzorzec strukturalny, który zapewnia zunifikowany interfejs do złożonego podsystemu klas. Ma na celu uproszczenie korzystania z podsystemu, ukrywając jego złożoność przed klientem.

Moje doświadczenie z wzorcem Facade obejmowało na przykład pracę z architekturą wielowarstwową w aplikacji. Załóżmy, że był moduł do pracy z siecią i bazą danych. Zamiast, aby kod klienta bezpośrednio wchodził w interakcję z klasami warstwy sieciowej (Retrofit, OkHttp), parserami, klasami bazy danych (Room, DAO), zaimplementowano klasę fasadę. Ta fasada zapewniała proste metody, np. getUser(userId) lub saveUser(user), które wewnętrznie koordynowały interakcję z odpowiednimi podsystemami: wykonywały zapytanie sieciowe, analizowały dane, zapisywały w bazie danych.

Zalety takiego podejścia:

  • Uproszczenie kodu klienta: Klient nie musi znać wewnętrznej struktury podsystemu.
  • Zmniejszenie powiązań: Fasada oddziela klienta od konkretnych implementacji podsystemu, co ułatwia ich wymianę.
  • Poprawa struktury: Podsystem staje się bardziej zarządzalny i zrozumiały.

Przykład uproszczonej implementacji fasady:

// Podsystem obsługi API
class ApiService {
    fun getUserFromApi(userId: Int): String {
        // Logika zapytania sieciowego
        return "{\"id\":$userId, \"name\":\"John Doe\"}"
    }
}

// Podsystem obsługi bazy danych
class DatabaseService {
    fun saveUserToDb(userJson: String) {
        // Logika zapisywania do bazy danych
    }

    fun getUserFromDb(userId: Int): String {
        // Logika pobierania z bazy danych
        return "" // Placeholder
    }
}

// Fasada
class UserFacade(
    private val apiService: ApiService,
    private val databaseService: DatabaseService
) {
    fun getUser(userId: Int): String {
        // Najpierw próbujemy pobrać z bazy danych
        val userFromDb = databaseService.getUserFromDb(userId)
        if (userFromDb.isNotEmpty()) {
            return userFromDb
        }

        // Jeśli nie ma w bazie, pobieramy z API
        val userFromApi = apiService.getUserFromApi(userId)

        // Zapisujemy w bazie dla cache
        databaseService.saveUserToDb(userFromApi)

        return userFromApi
    }
}

// Przykład użycia fasady w kodzie klienta
fun main() {
    val apiService = ApiService()
    val databaseService = DatabaseService()
    val userFacade = UserFacade(apiService, databaseService)

    val userJson = userFacade.getUser(123)
    println(userJson)
}

W tym przykładzie UserFacade ukrywa szczegóły pobierania danych użytkownika z API i zapisywania ich w bazie danych, zapewniając klientowi prostą metodę getUser. Klient nie musi znać istnienia ApiService i DatabaseService.

W ten sposób, Facade pomaga tworzyć bardziej czysty, zrozumiały i łatwy do utrzymania kod, szczególnie przy pracy z złożonymi modułami.