Kontrol Sistemleri ve Otomasyon
Kotlin'deki Abstract Factory Desen ile Esnek Bildirim Sistemi Tasarlamak
Table of Contents
Modern uygulamalar, birçok kanalda mesajları teslim edebilecek sağlam bildirim sistemleri gerektirir - e-posta, SMS, uyarıları itmek, Slack ve daha fazlası. Temel zorluk, Kotlin'in dil özelliklerini kullanarak Kotlin'in dil özelliklerini kullanarak ortaya çıkan bir sistem inşa eder.
Özet Fabrika Desenini Anlamak
Özet Fabrika modeli, dört çetesinden orijinal yaratım desenlerinden biridir. Beton sınıflarını belirtmeden ilgili veya bağlı nesnelere ait aileler oluşturmak için bir arayüz sunar.
- Bir sistem, ürünlerinin nasıl yaratıldığı, oluştuğu veya temsil edildiğinden bağımsız olmalıdır.
- Bir sistem, birden çok ürün ailesi ile yapılandırılmalıdır.
- Birlikte ait ürünler arasında tutarlılığı uygulamak istiyorsunuz.
- Yeni ürün ailelerine sık sık sık ekliyorsunuz ve mevcut kodu değiştirmekten kaçınmak istiyorsunuz.
Desenler
- [FONT:0)Abstract (Dönetici))[FONT: Her biri soyut bir ürün geri döndürür.
- [FONT:0)ConcreteMaster[[Dönetici:0)[Döneticileri üretmek için yaratım yöntemlerini uygular.
- [FONT:0)AbstractÜrün[[DÜT:1]: Bir ürün nesnesi türü için bir arayüz ilan eder.
- [[Düzzaman:0)ConcreteProduct[Dönesel:0)[Dönlü Ürün[Dönlümler: Özet Ürün arayüzünü uygulayan bir ürün nesneyi tanımlar.
- [FONT:0)Client[[DÜT:1): AbstractF ve AbstractProduct tarafından ilan edilen sadece arayüzler kullanır.
Bir bildirim sistemi bağlamında, [[Üyetim:0)Abstract[DÜye Olmayanlar[Üye Olmayanlar İçindekiler:0) arayüz ve [[Dönetici[DÜye Olmayanlar İçindekiler)[Üye Olmayanlar İçindekiler (DÜye Olmayanlar)[Üye Olmayanlar İçindekiler (Dönemli Ürünler)
Tasarım Desen Uygulaması için Kotlin Neden?
Kotlin, Özet Fabrika modelini Java'dan daha fazla koncise ve daha güvenli hale getiren birkaç modern dil özelliği getiriyor:
- [FONT:0]Denizli sınıflar[[Dönemli bir bildirim türü temsil etmek için, kapalı bir bildirim türünü temsil etmek için, egz.D:0) ifadelere izin vermek.
- [FONT:0]Data classes[[Döneticileri) ürün uygulamalarında kazanım işlemini azaltmak için.
- [FONT:0)Object Açıklamaları[Dönemli fabrikalar oluşturmak için[Dönemli)
- [FONT:0) Yüksek sipariş işlevleri[[[Dönetici:0) uygun olduğunda fabrika arayüzlerini koyun fabrikalarında değiştirmek için.
- [FONT:0]Null güvenlik) ve [[Dönetici:2)) Runtime hataları azaltmak için [DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDÜSÜDÜSÜSÜSÜSÜSÜSÜSÜSÜSÜSÜSÜSÜSÜSÜSÜSÜSÜSÜSÜSÜSÜSÜSÜSÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜN
Bu özellikler sadece esnek değil aynı zamanda derleme-zaman güvenli olan bir fabrika sistemi yazmanıza izin verir, yansıma veya koşu zaman tipi çeklere ihtiyaç duyar.
Özet Fabrika ile Core Bildirim Sistemi Yapın
Kotlin'de bir adım adım adım uygulama ile yürüyelim. En az versiyonla başlayacağız ve sonra gerçek dünya karmaşıklığını ele almak için genişleteceğiz.
1. Özet Ürün Interface'i Tanımlayın
Her bildirim bir dörFLT:5'ı ortaya çıkarmak zorundadır. Ayrıca, routing ve log desteği için bir mülk de dahil ediyoruz.
interface Notification {
val type: String
fun send(message: String): Result
}
data class Result(val success: Boolean, val error: String? = null)
2. Implement Concrete Products
Kotlin'in koncisemi kullanarak, e-posta, SMS için beton uygulamaları yaratıyoruz ve bildirimler itiyoruz. Gerçekizm için her uygulama gerçek API çağrılarını içeriyor, ancak burada onları simüle ediyoruz.
class EmailNotification : Notification {
override val type = "email"
override fun send(message: String): Result {
// Simulate sending email via SMTP or service like SendGrid
println("Sending email: $message")
return Result(true)
}
}
class SmsNotification : Notification {
override val type = "sms"
override fun send(message: String): Result {
// Simulate sending SMS via Twilio or similar
println("Sending SMS: $message")
return Result(true)
}
}
class PushNotification : Notification {
override val type = "push"
override fun send(message: String): Result {
// Simulate sending push via Firebase Cloud Messaging
println("Sending push notification: $message")
return Result(true)
}
}
3. Özet Fabrika Interface
Fabrika tek bir yaratım yöntemi ilan ediyor. Daha karmaşık sistemlerde, birden fazla yaratım yöntemine sahip olabilirsiniz (örneğin, 03: 00).
interface NotificationFactory {
fun createNotification(): Notification
}
4. Implement Concrete Factories
Her fabrika tam bir ürün türü kullanarak anında sorumludur. birİLRAT:12 kullanarak, bu fabrikayı genellikle yeterli olan tekton yapar.
object EmailNotificationFactory : NotificationFactory {
override fun createNotification(): Notification = EmailNotification()
}
object SmsNotificationFactory : NotificationFactory {
override fun createNotification(): Notification = SmsNotification()
}
object PushNotificationFactory : NotificationFactory {
override fun createNotification(): Notification = PushNotification()
}
5. Müşteri Kodlarından Faktörleri Kullanın
Müşteri (örneğin, bir bildirim hizmeti) bir uyarıyı kabul eder ve beton ürün sınıfı bilmeden bir mesaj gönderir.
fun sendNotification(factory: NotificationFactory, message: String) {
val notification = factory.createNotification()
val result = notification.send(message)
if (!result.success) {
println("Failed to send ${notification.type}: ${result.error}")
}
}
fun main() {
// In a real app, the factory choice would come from configuration or user preferences
sendNotification(EmailNotificationFactory, "Welcome to our service!")
sendNotification(SmsNotificationFactory, "Your code is 1234")
sendNotification(PushNotificationFactory, "New message from Bob")
}
Bu temel kurulum zaten modelin gücünü gösteriyor: yeni bir kanal ekliyor (örneğin, Slack) sadece yeni bir ürün sınıfı ve yeni bir fabrika gerektirir - müşteri kodu veya mevcut fabrikalara değişiklikler yoktur.
Sistemi Yeni Bildirim Kanalları ile uzatın
Slack bildirimlerini eklememiz gerektiğini varsayalım. ” ve [[DÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜ
class SlackNotification(private val webhookUrl: String) : Notification {
override val type = "slack"
override fun send(message: String): Result {
// POST to webhookUrl
return if (webhookUrl.isNotBlank()) {
println("Sending Slack message: $message")
Result(true)
} else {
Result(false, "Webhook URL not configured")
}
}
}
object SlackNotificationFactory : NotificationFactory {
override fun createNotification(): Notification = SlackNotification(CONFIG_SLACK_WEBHOOK)
}
Müşteri kodu hala devam ediyor. Bu, Open/Kapatlanmış Prensipinin eylemdeki yeridir: Sistem uzatma için açık ancak değişiklik için kapalıdır.
Prodüksiyon-Ready Systems için Gelişmiş Düşünmeler
Temel desen işe yarasa da, gerçek dünya bildirim sistemleri daha fazla bu kadarphistasyon talep ediyor. Kotlin özelliklerini kullanarak geliştirmeleri keşfedelim.
Eğlenmeli Fabrika Seçimi için Dersler
Bir soyut fabrikayı geçmek yerine, Kotlin'in dördünü GÖRÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞ
sealed class NotificationType {
object Email : NotificationType()
object SMS : NotificationType()
object Push : NotificationType()
data class Slack(val webhookUrl: String) : NotificationType()
}
fun createNotification(type: NotificationType): Notification = when (type) {
NotificationType.Email -> EmailNotification()
NotificationType.SMS -> SmsNotification()
NotificationType.Push -> PushNotification()
is NotificationType.Slack -> SlackNotification(type.webhookUrl)
}
Bu yaklaşım ayrı fabrika arayüzünü ortadan kaldırır ve bunun yerine doğru ürünü geri döndüren tek bir işlev kullanır. Küçük ila orta sistemler için daha basit ve size zaman güvenliği derletirir.
Asynchronous Bildirim Göndering
Çoğu bildirim kanalı ağ çağrılarını içerir. Returningurly pratik değildir. yerine, akoroutine askıya alma veya geri dönme yöntemi.
interface Notification {
suspend fun send(message: String): Result
}
class EmailNotification : Notification {
override suspend fun send(message: String): Result {
// Use Http client to send email
return withContext(Dispatchers.IO) {
// actual API call
Result(true)
}
}
}
Müşteri kodu daha sonra bir koroutine kapsamından “Ücretim” olarak adlandırabilir:
suspend fun sendNotification(factory: NotificationFactory, message: String) {
val notification = factory.createNotification()
val result = notification.send(message)
// handle result
}
Bağlanma Enjeksiyonu Entegrasyon
Sert kodlanmış fabrikalar yerine, Koin veya Dagger gibi bir bağımlılık enjeksiyon çerçevesini fabrikaları arayüzize etmek için kullanın.Bu, testlerde veya konfigürasyonlarda uygulamalarınızı değiştirmenize olanak sağlar.
// Koin module
val notificationModule = module {
factory<NotificationFactory>("email") { EmailNotificationFactory }
factory<NotificationFactory>("sms") { SmsNotificationFactory }
factory<NotificationFactory>("push") { PushNotificationFactory }
}
Sonra Koin'den bir yapılandırma anahtarına dayanan doğru fabrikayı elde edin.
Hata işleme ve Yenidenleme
Bildirimler genellikle geçici hatalar nedeniyle başarısız olur. fabrika ve ürün oluşturma hata işleme ile yapılır. Ayrıca Kotlin koroutines'un “İLFLT:30” inşaatçısını kullanarak yeniden deneme mekanizması uygulayabilirsiniz.
suspend fun sendWithRetry(factory: NotificationFactory, message: String, maxRetries: Int = 3): Result {
repeat(maxRetries) { attempt ->
try {
val notification = factory.createNotification()
return notification.send(message)
} catch (e: Exception) {
if (attempt == maxRetries - 1) {
return Result(false, e.message)
}
delay(1000L * (attempt + 1)) // exponential backoff
}
}
return Result(false, "Max retries exceeded")
}
Şablon ve kişiselleştirme
Bildirimler genellikle cazip (örneğin, HTML e-posta, dinamik SMS içeriği) Fabrika bir şablon motoru ile önceden yapılandırılmış bir bildirim nesnesini geri döndürebilir. Örneğin:
class TemplatedEmailNotification(private val template: String) : Notification {
override val type = "email"
override fun send(message: String): Result {
val body = processTemplate(template, mapOf("content" to message))
// Send email with rendered body
return Result(true)
}
}
Fabrika daha sonra ek parametrelere dayanan farklı ürün çeşitleri yaratabilir.
Bildirim Sistemini Test Etmek
Özet Fabrika deseninin en büyük faydalarından biri test edilebilir. Test çiftlerini geri dönen kriminal fabrikaları kolayca oluşturabilirsiniz.
class MockNotification : Notification {
var sentMessage: String? = null
override val type = "mock"
override fun send(message: String): Result {
sentMessage = message
return Result(true)
}
}
object MockNotificationFactory : NotificationFactory {
val mock = MockNotification()
override fun createNotification(): Notification = mock
}
// In test:
val factory = MockNotificationFactory
sendNotification(factory, "Test message")
assertEquals("Test message", factory.mock.sentMessage)
Ayrıca fabrikayı doğru ürün türü geri döndüren birim testleri yazabilirsiniz, Kotlin'in 03:34 numaralı stili maççılar kullanarak.
Runtime'daki Faktörleri Yeniden Tanımlayın
Mikro hizmet mimarisinde, bildirim kanalı seçimi bir yapılandırma dosyası, çevre değişkeni veya veritabanından gelebilir. haritaları fabrika örneklerine gösteren bir kayıt uygulayabilirsiniz.
object NotificationFactoryRegistry {
private val factories = mutableMapOf<String, NotificationFactory>()
fun register(channel: String, factory: NotificationFactory) {
factories[channel] = factory
}
fun getFactory(channel: String): NotificationFactory? = factories[channel]
}
Ardından kayıt defterini, başvuru başlangıçını [[DüzDÜDÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜye Bilgi Sisteminin tamamının kullanması için hangi fabrikanın kararını tamamen ikiye katlayın.
Fabrika Yöntemi ile Karşılaştırma
Özet Fabrika modeli genellikle daha basit Fabrika Yöntemiyle karıştırılır. Anahtar fark, Fabrika Yönteminin tek bir ürünle ilgili ürünlerle ilgili olarak, bildirim sistemimizde, kanal başına birden çok ilgili ürüne sahipseniz (örneğin, bu kanalda tutarlılık ve bir yetenek) ihtiyacınız varsa, Abstract Factory'yi tek bir ürün için kullanabilirsiniz.
Bütün Birlikte Oluşturun: Gerçek Bir Dünya Örneği
Kullanıcıların bildirim tercihlerini seçmelerine izin veren bir SaaS platformu düşünün: e-posta, SMS, iter veya Slack. Sistem bir veritabanından kullanıcı tercihlerini okur, bir kayıt işlemine (ya da kayıt yaptırma) izin vermez ve bildirimini gönderin. Abstract Factory modelini kullanarak, yeni bir kanal (say, Microsoft Teams) sadece yeni bir ürün sınıfı ve yeni bir USBT:37 gerektirir - ve bu belgeye kayıt olun.
// Preference model
data class UserPreference(
val userId: String,
val channel: String // "email", "sms", "push", "slack"
)
class NotificationDispatcher(private val registry: NotificationFactoryRegistry) {
suspend fun dispatch(preference: UserPreference, message: String) {
val factory = registry.getFactory(preference.channel)
?: throw IllegalArgumentException("Unknown channel: ${preference.channel}")
val notification = factory.createNotification()
notification.send(message)
}
}
Bu tasarım sadece esnek değil aynı zamanda son derece test edilebilir: Kayıtları alay edebilir ve doğru fabrikanın her kanal için kullanıldığını doğrulayabilirsiniz.
Kotlin'de Özet Fabrikayı Uygulamak için En İyi Uygulamalar
- [FONT:0)Öyle mühürlenen sınıflar gevşek arayüz tanımları[Dön 1: 1], ürün setleri kapalı ve derleyici zaman zamanlandığında size yorucu kontroller verir.
- [FONT:0) Arkadaş nesneleri veya nesne bildirimlerini kullanın[Dönetici olmayan fabrikalar için). Bu gereksiz nesne yaratımından kaçınır.
- [[Düzücü varsayılan parametre değerleri[[Dönlendirme): Ürün inşaörlerinde aşırı yükleme fabrikaları olmadan mantıklı varsayılan varsayılan varsayılan varsayılanlar sağlamak için.
- [FONT:0) Fabrika arayüzünü minimum tut.Eğer birçok yaratım yöntemi eklerseniz, bir inşaat modeli veya yapılandırma nesnesini kullanmayı düşünün.
- [FONT:0)MakeurFLT:39) işlevleri askıya alındı[DÜT 1: 1 ), iplikleri engellemekten kaçınmak için. Kotlin koroutines doğal olarak Abstract Factory gibi desenlerle bütünleştirir.
- [FONT:0) Her fabrikanın ve ürününin sorumluluklarını[Döneticileri) saklı tutar. Çünkü desen, iki yönlü, net adlandırma ve belgelemenin temel olduğunu gösterir.
Dış Kaynaklar
Özet Fabrika deseninin ve Kotlin'deki uygulamalarınızın anlaşılmasını derinleştirmek için aşağıdaki kaynaklara atıfta bulun:
- [FONT:0)Abstract Factory Deseni - Refaktoring Guru) - UML diyagramları ve kod örnekleri ile kapsamlı bir açıklama.
- [FONT:0]Kotlin Sealed Sınıflar[[Dönemli Sınıflar 1 ) – Kapalı sınıfların sınıf hiyerarşilerini nasıl modelleyebileceği konusunda resmi belgeler.
- [FONT=0]Kotlin in Action[Dönetici: 1 ) – tasarım desen uygulamaları da dahil olmak üzere Kotlin'deki kesin kitap (Chapter 11 kapak kalıpları).
Kotlin'in modern dili özellikleri ile kanıtlanmış Abstract Factory modelini birleştirerek, sadece esnek ve ölçeklenebilir olmayan bir bildirim sistemi inşa edebilirsiniz, aynı zamanda güvenli ve kullanılabilir. iki kanal veya yirmi desteklerseniz, desen yeni yetenekleri asla yeniden yazmayı hissetmez - öngörülebilir, düşük riskli bir uzatma haline gelir.