Alan katmanı

Alan adı katmanı, kullanıcı arayüzü katmanı ile veri katmanı arasında yer alan isteğe bağlı bir katmandır.

İsteğe bağlı alan katmanı, dahil edildiğinde kullanıcı arayüzü katmanına bağımlılıklar sağlar ve veri katmanına bağlıdır.
Şekil 1. Alan katmanının uygulama mimarisindeki rolü.

Alan adı katmanı, karmaşık iş mantığını veya birden fazla ViewModel tarafından yeniden kullanılan basit iş mantığını kapsamaktan sorumludur. Bu gereksinimler tüm uygulamalarda olmayacağından bu katman isteğe bağlıdır. Yalnızca gerektiğinde (örneğin, karmaşıklığı yönetmek veya yeniden kullanılabilirliği tercih etmek için) kullanmalısınız.

Alan adı katmanı aşağıdaki avantajları sağlar:

  • Kodların yinelenmesini önler.
  • Alan katmanı sınıflarının kullanıldığı sınıflarda okunabilirliği artırır.
  • Uygulamanın test edilebilirliğini iyileştirir.
  • Sorumlulukları bölmenize imkan tanıyarak büyük sınıfların oluşumunu önler.

Bu sınıfların basit ve küçük kalmasını sağlamak amacıyla, her kullanım alanı yalnızca tek bir işlev üzerinde sorumluluğa sahip olmalı ve değişken veriler içermemelidir. Bunun yerine, kullanıcı arayüzünüzde veya veri katmanlarınızda değişken verileri işlemeniz gerekir.

Bu kılavuzdaki adlandırma kuralları

Bu kılavuzda, kullanım alanları sorumlu oldukları tek işlemden sonra adlandırılmıştır. Sistem aşağıdaki gibidir:

mevcut zamandaki fiil + isim/ne (isteğe bağlı) + Kullanım alanı.

Örneğin: FormatDateUseCase, LogOutUserUseCase, GetLatestNewsWithAuthorsUseCase veya MakeLoginRequestUseCase.

Bağımlılıklar

Tipik bir uygulama mimarisinde, kullanım alanı sınıfları, kullanıcı arayüzü katmanındaki ViewModel'ler ile veri katmanındaki depolar arasında yer alır. Bu, kullanım alanı sınıflarının genellikle depo sınıflarına bağlı olduğu ve geri çağırma (Java için) ya da eş kotinler (Kotlin için) kullanarak aynı şekilde depoların yaptığı şekilde kullanıcı arayüzü katmanıyla iletişim kurduğu anlamına gelir. Bu konu hakkında daha fazla bilgi için veri katmanı sayfasını inceleyin.

Örneğin, uygulamanızda, bir haber deposu ile bir yazar deposundan veri getiren ve bunları birleştiren bir kullanım alanı sınıfınız olabilir:

class GetLatestNewsWithAuthorsUseCase(
  private val newsRepository: NewsRepository,
  private val authorsRepository: AuthorsRepository
) { /* ... */ }

Kullanım alanları yeniden kullanılabilir mantık içerdiğinden, diğer kullanım alanları tarafından da kullanılabilir. Alan adı katmanında birden çok kullanım alanı düzeyine sahip olması normaldir. Örneğin, aşağıdaki örnekte tanımlanan kullanım alanı, kullanıcı arayüzü katmanındaki birden fazla sınıf ekranda doğru mesajı görüntülemek için saat dilimlerine ihtiyaç duyuyorsa FormatDateUseCase kullanım alanından yararlanabilir:

class GetLatestNewsWithAuthorsUseCase(
  private val newsRepository: NewsRepository,
  private val authorsRepository: AuthorsRepository,
  private val formatDateUseCase: FormatDateUseCase
) { /* ... */ }
GetNewNewsWithAuthorsUseCase, veri katmanındaki depo sınıflarına bağlıdır ancak aynı zamanda alan katmanında bulunan başka bir kullanım alanı sınıfı olan FormatDataUseCase'a da bağlıdır.
Şekil 2. Bir kullanım alanı için başka kullanım alanlarına bağlı olan örnek bağımlılık grafiği.

Kotlin'de telefon araması kullanım alanları

Kotlin'de invoke() işlevini operator değiştiriciyle tanımlayarak kullanım alanı sınıfı örneklerini işlev olarak çağırılabilir hale getirebilirsiniz. Aşağıdaki örneğe bakın:

class FormatDateUseCase(userRepository: UserRepository) {

    private val formatter = SimpleDateFormat(
        userRepository.getPreferredDateFormat(),
        userRepository.getPreferredLocale()
    )

    operator fun invoke(date: Date): String {
        return formatter.format(date)
    }
}

Bu örnekte, FormatDateUseCase bölümündeki invoke() yöntemi, sınıfın örneklerini işlevlermiş gibi çağırmanızı sağlar. invoke() yöntemi, belirli bir imzayla sınırlı değildir. Herhangi bir sayıda parametre alıp herhangi bir türü döndürebilir. Ayrıca sınıfınızda invoke() ürününe farklı imzalar ekleyebilirsiniz. Yukarıdaki örnekte verilen kullanım alanını aşağıdaki şekilde çağırırsınız:

class MyViewModel(formatDateUseCase: FormatDateUseCase) : ViewModel() {
    init {
        val today = Calendar.getInstance()
        val todaysDate = formatDateUseCase(today)
        /* ... */
    }
}

invoke() operatörü hakkında daha fazla bilgi edinmek için Kotlin belgelerine bakın.

Yaşam döngüsü

Kullanım alanlarının kendi yaşam döngüleri yoktur. Bunun yerine, kapsam, bunları kullanan sınıflara ayarlanır. Yani kullanım alanlarını kullanıcı arayüzü katmanındaki sınıflar, hizmetler veya Application sınıfının kendisinden çağırabilirsiniz. Kullanım alanlarının değişken veriler içermemesi gerektiğinden, bağımlılık olarak geçirdiğiniz her defasında kullanım alanı sınıfının yeni bir örneğini oluşturmanız gerekir.

İplik işleme

Alan katmanındaki kullanım alanları main-safe olmalıdır. Diğer bir deyişle, ana iş parçacığından çağrılmanın güvenli olması gerekir. Kullanım alanı sınıfları uzun süreli engelleme işlemleri gerçekleştiriyorsa bu mantığı uygun iş parçacığına taşımaktan sorumludur. Ancak bunu yapmadan önce, bu engelleme işlemlerinin hiyerarşinin diğer katmanlarına daha iyi yerleştirilip yerleştirilmeyeceğini kontrol edin. Genel olarak, yeniden kullanılabilirliği veya önbelleğe almayı teşvik etmek için veri katmanında karmaşık hesaplamalar gerçekleşir. Örneğin, büyük bir listedeki kaynak yoğun bir işlem, sonucun uygulamanın birden fazla ekranında yeniden kullanılması için önbelleğe alınması gerekiyorsa alan katmanı yerine veri katmanına daha iyi yerleştirilir.

Aşağıdaki örnekte, bir arka plan iş parçacığı üzerinde çalışan bir kullanım alanı gösterilmektedir:

class MyUseCase(
    private val defaultDispatcher: CoroutineDispatcher = Dispatchers.Default
) {

    suspend operator fun invoke(...) = withContext(defaultDispatcher) {
        // Long-running blocking operations happen on a background thread.
    }
}

Genel görevler

Bu bölümde, sık kullanılan alan adı katmanı görevlerinin nasıl gerçekleştirileceği açıklanmaktadır.

Yeniden kullanılabilir basit iş mantığı

Kullanım alanı sınıfında, kullanıcı arayüzü katmanında bulunan tekrarlanabilir iş mantığını özetlemeniz gerekir. Bu, mantığın kullanıldığı her yerde değişikliklerin uygulanmasını kolaylaştırır. Ayrıca, mantığı tek başına test etmenize de olanak tanır.

Daha önce açıklanan FormatDateUseCase örneğini inceleyin. Tarih biçimlendirmeyle ilgili işletmenizin ihtiyaçları gelecekte değişirse kodu yalnızca tek bir merkezi yerden değiştirmeniz gerekir.

Depoları birleştirme

Bir haber uygulamasında, haber ve yazar verisi işlemlerini işleyen sırasıyla NewsRepository ve AuthorsRepository sınıflarınız olabilir. NewsRepository tarafından sunulan Article sınıfı yalnızca yazarın adını içerir ancak ekranda yazar hakkında daha fazla bilgi görüntülemek istiyorsunuz. Yazar bilgileri AuthorsRepository adresinden elde edilebilir.

GetLastNewsWithAuthorsUseCase, veri katmanından iki farklı depo sınıfına bağlıdır: NewsRepository ve AuthorsRepository.
Şekil 3. Birden fazla depodaki verileri birleştiren bir kullanım alanı için bağımlılık grafiği.

Mantık, birden çok depo içerdiği ve karmaşık hale gelebileceği için, mantığı ViewModel'den soyutlamak ve daha okunabilir hale getirmek için bir GetLatestNewsWithAuthorsUseCase sınıfı oluşturursunuz. Bu, mantığın tek başına test edilmesini de kolaylaştırır ve uygulamanın farklı bölümlerinde yeniden kullanılabilir.

/**
 * This use case fetches the latest news and the associated author.
 */
class GetLatestNewsWithAuthorsUseCase(
  private val newsRepository: NewsRepository,
  private val authorsRepository: AuthorsRepository,
  private val defaultDispatcher: CoroutineDispatcher = Dispatchers.Default
) {
    suspend operator fun invoke(): List<ArticleWithAuthor> =
        withContext(defaultDispatcher) {
            val news = newsRepository.fetchLatestNews()
            val result: MutableList<ArticleWithAuthor> = mutableListOf()
            // This is not parallelized, the use case is linearly slow.
            for (article in news) {
                // The repository exposes suspend functions
                val author = authorsRepository.getAuthor(article.authorId)
                result.add(ArticleWithAuthor(article, author))
            }
            result
        }
}

Mantık, news listesindeki tüm öğeleri eşler. Bu nedenle, veri katmanı ana güvenli olsa da, kaç öğe işleyeceğini bilmediğiniz için bu iş, ana iş parçacığını engellememelidir. Bu nedenle kullanım alanında, varsayılan görev dağıtıcıyı kullanarak iş bir arka plan iş parçacığına taşınır.

Diğer tüketiciler

Alan katmanı, kullanıcı arayüzü katmanından ayrı olarak hizmetler ve Application sınıfı gibi diğer sınıflar tarafından yeniden kullanılabilir. Dahası, TV veya Wear gibi diğer platformlar kod tabanını mobil uygulamayla paylaşıyorsa bu platformların kullanıcı arayüzü katmanları, alan katmanının yukarıda belirtilen tüm avantajlarından yararlanmak için kullanım alanlarını da yeniden kullanabilir.

Veri katmanı erişim kısıtlaması

Alan katmanını uygularken dikkat edilmesi gereken diğer bir nokta da, kullanıcı arayüzü katmanından veri katmanına doğrudan erişime izin vermeniz veya alan katmanındaki her şeyi zorunlu kılmanızdır.

Kullanıcı arayüzü katmanı veri katmanına doğrudan erişemez, Alan katmanından geçmesi gerekir
Şekil 4. Kullanıcı arayüzü katmanının veri katmanına erişiminin reddedilmesini gösteren bağımlılık grafiği.

Bu kısıtlamayı uygulamanın bir avantajı, kullanıcı arayüzünüzün alan katmanı mantığını atlamasını engellemesidir. Örneğin, veri katmanına yapılan her erişim isteğinde analiz günlüğü kaydı gerçekleştiriyorsanız bu kısıtlamayı uygulama, kullanıcı arayüzünüzün alan katmanı mantığını atlamasını engeller.

Bununla birlikte, muhtemelen önemli dezavantajı, veri katmanına sadece basit işlev çağrıları olduğunda bile kullanım alanları eklemenizi gerektirmesidir, bu da çok az fayda sağlayacak şekilde karmaşık hale getirebilir.

Kullanım alanlarını yalnızca gerektiğinde eklemek iyi bir yaklaşımdır. Kullanıcı arayüzü katmanınızın verilere neredeyse yalnızca kullanım alanları üzerinden eriştiğini tespit ederseniz verilere yalnızca bu şekilde erişmek mantıklı olabilir.

Sonuç olarak, veri katmanına erişimi kısıtlama kararı bireysel kod tabanınıza ve katı kuralları mı yoksa daha esnek bir yaklaşımı mı tercih ettiğinize bağlıdır.

Test

Genel test kılavuzu, alan katmanı test edilirken geçerlidir. Diğer kullanıcı arayüzü testlerinde, geliştiriciler genellikle sahte depolar kullanır. Bu nedenle, alan katmanını test ederken de sahte depolar kullanmak iyi bir uygulamadır.

Sana Özel

Aşağıdaki Google örnekleri, alan adı katmanının kullanımını göstermektedir. Bu kılavuzu inceleyerek örnekleri inceleyin: