Alan katmanı

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

Eklendiğinde isteğe bağlı alan katmanı, kullanıcı arayüzü katmanına bağımlılıklar sağlar ve veri katmanına bağlıdır.
Şekil 1. Alan adı 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ı kapsüllemekten sorumludur. Tüm uygulamalar bu gereksinimlere sahip olmadığından bu katman isteğe bağlıdır. Bunu 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 iyileştirir.
  • Uygulamanın test edilebilirliğini artırır.
  • Sorumlulukları bölüştürmenize olanak tanıyarak büyük çaplı sınıflardan kaçınır.

Bu sınıfların basit ve hafif olması için her kullanım alanı yalnızca tek bir işlevden sorumlu olmalı ve değişken veriler içermemelidir. Bunun yerine, kullanıcı arayüzünüzdeki veya veri katmanlarındaki değişken verileri işlemelisiniz.

Bu kılavuzdaki adlandırma kuralları

Bu kılavuzda, kullanım alanları sorumlu oldukları tek işlemin adını almıştır. Kural aşağıdaki gibidir:

şimdiki zaman fiil + isim/ne (isteğe bağlı) + UseCase.

Ö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ına sığar. Bu, kullanım alanı sınıflarının genellikle depo sınıflarına bağlı olduğu ve kullanıcı arayüzü katmanıyla, depolarla aynı şekilde iletişim kurabileceği anlamına gelir. Geri çağırma (Java için) veya kotlin (Kotlin için) kullanılır. Bu konu hakkında daha fazla bilgi için veri katmanı sayfasına bakın.

Örneğin, uygulamanızda, bir haber deposundan ve 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ği için başka kullanım alanları tarafından da kullanılabilir. Alan adı katmanında birden çok düzeyde kullanım alanının olması normaldir. Örneğin, aşağıdaki örnekte tanımlanan kullanım alanında, kullanıcı arayüzü katmanındaki birden fazla sınıf ekranda uygun mesajı göstermek için saat dilimlerinden yararlanan FormatDateUseCase kullanım alanı kullanılabilir:

class GetLatestNewsWithAuthorsUseCase(
  private val newsRepository: NewsRepository,
  private val authorsRepository: AuthorsRepository,
  private val formatDateUseCase: FormatDateUseCase
) { /* ... */ }
GetLastNewsWithAuthorsUseCase, 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. Diğer kullanım alanlarına bağlı olan bir kullanım alanı için örnek bağımlılık grafiği.

Kotlin'deki 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 öğesindeki invoke() yöntemi, sınıfın örneklerini işlev gibi çağırmanıza olanak tanır. invoke() yöntemi belirli bir imzayla sınırlı değildir. İstediğiniz sayıda parametre alabilir ve herhangi bir türü döndürebilir. Ayrıca, sınıfınızda farklı imzalarla invoke() uygulamasını basit bir şekilde yükleyebilirsiniz. Yukarıdaki örnekte verilen kullanım alanını şu şekilde çağırabilirsiniz:

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üsü yoktur. Bunun yerine, ilgili sınıfların kapsamına alınırlar. Bu, kullanıcı arayüzü katmanındaki sınıflardan, hizmetlerden veya Application sınıfının kendisinden kullanım alanlarını çağırabileceğiniz anlamına gelir. Kullanım alanlarının değişebilir veriler içermemesi gerektiğinden, bağımlılık olarak her ilettiğinizde kullanım alanı sınıfının yeni bir örneğini oluşturmalısınız.

İleti dizisi

Alan katmanındaki kullanım alanları main-güvenli olmalıdır; başka bir deyişle, ana iş parçacığından çağrı yapmak için güvenli olmalıdır. 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 bir şekilde yerleştirilip yerleştirilmeyeceğini kontrol edin. Karmaşık hesaplamalar genellikle yeniden kullanılabilirliği veya önbelleğe almayı teşvik etmek için veri katmanında 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ılabilmesi için önbelleğe alınması gerekiyorsa veri katmanına alan katmanına yerleştirilmesinden daha iyi olur.

Aşağıdaki örnekte, çalışmasını arka plan iş parçacığı üzerinde gerçekleştiren 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 katmanı görevlerinin nasıl gerçekleştirileceği açıklanmaktadır.

Yeniden kullanılabilir, basit iş mantığı

Kullanıcı arayüzü katmanında bulunan tekrarlanabilir iş mantığını bir kullanım alanı sınıfına dahil etmeniz gerekir. Bu, mantığın kullanıldığı her yerde herhangi bir değişikliğin 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 göz önünde bulundurun. Gelecekte tarih biçimlendirmesi ile ilgili iş gereksinimleriniz değişirse kodu yalnızca tek bir merkezi yerde değiştirmeniz gerekir.

Depoları birleştirme

Bir haber uygulamasında, sırasıyla haber ve yazar verisi işlemlerini işleyen NewsRepository ve AuthorsRepository sınıflarınız olabilir. NewsRepository ürününün gösterdiği Article sınıfı yalnızca yazarın adını içeriyor, ancak siz ekranda yazar hakkında daha fazla bilgi görüntülemek istiyorsunuz. Yazar bilgileri AuthorsRepository kaynağından edinilebilir.

GetLastNewsWithAuthorsUseCase, veri katmanındaki 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 fazla 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 aynı zamanda, mantığın ayrı olarak 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. Böylece veri katmanı ana iş parçacığı olarak güvenli olsa da, kaç öğe işleyeceğini bilmediğiniz için bu işin ana iş parçacığını engellememesi gerekir. Bu nedenle, kullanım alanı, varsayılan sevk aracını kullanarak çalışmayı arka plandaki bir iş parçacığına taşır.

Diğer tüketiciler

Alan adı katmanı, kullanıcı arayüzü katmanı dışında, hizmetler ve Application sınıfı gibi diğer sınıflar tarafından yeniden kullanılabilir. Ayrıca TV veya Wear gibi diğer platformlar kod tabanını mobil uygulamayla paylaşırsa kullanıcı arayüzü katmanı, 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ı uygulanırken göz önünde bulundurulması gereken bir diğer nokta da kullanıcı arayüzü katmanından veri katmanına doğrudan erişim izni vermeniz veya her şeyi alan katmanı yoluyla zorunlu kılmanız gerektiğidir.

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

Bu kısıtlamayı yapmanın bir avantajı, örneğin veri katmanına yapılan her erişim isteğinde analiz günlük kaydı yapıyorsanız kullanıcı arayüzünüzün alan katmanı mantığını atlamasını engellemesidir.

Bununla birlikte, potansiyel olarak önemli bir dezavantajı, veri katmanına basit işlev çağrıları olduğunda bile sizi kullanım alanları eklemeye zorlamasıdır. Bu durum, fazla bir fayda sağlamadan karmaşıklığı artırabilir.

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

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

Test etme

Alan katmanı test edilirken genel test kılavuzu geçerlidir. Diğer kullanıcı arayüzü testleri için geliştiriciler genellikle sahte depolar kullanırlar ve alan katmanını test ederken de sahte depolar kullanmak iyi bir uygulamadır.

Numuneler

Aşağıdaki Google örnekleri, alan adı katmanının kullanımını göstermektedir. Uygulamadaki bu rehberliği görmek için bu yöntemleri inceleyin: