Table of Contents
יישומים מודרניים דורשים מערכות התראה חזקות המסוגלות להעביר מסרים על פני ערוצים מרובים - דואר אלקטרוני, SMS, הודעות דחיפה, Slack, ועוד.אתגר הליבה הוא לבנות מערכת שעדיין גמישה והחזקה כמו ערוצים חדשים מופיעים, מבלי לדרוש תיקון של הקוד הקיים.תבנית עיצוב המפעל הפשט מציע פתרון זמני במבחן זמן על ידי מתן ממשק ליצירת משפחות של אובייקטים הקשורים הפיכה ללא שימוש קוד לקוח ליישום מדויק.
הבנת תבנית המפעל
דפוס המפעל הפשט הוא אחד דפוסים הבריאה המקוריים של האנג' של ארבע.הוא מספק ממשק ליצירת משפחות של אובייקטים קשורים או תלויים מבלי לציין את שיעורי הבטון שלהם.התבנית היא שימושית במיוחד כאשר:
- מערכת חייבת להיות עצמאית של איך המוצרים שלה נוצרים, מורכבים או מיוצגים.
- יש להגדיר מערכת עם אחת ממשפחות מרובות של מוצרים.
- אתה רוצה לאכוף עקביות בין מוצרים השייכים יחד.
- אתה מוסיף משפחות מוצר חדשות לעתים קרובות, ואתה רוצה להימנע משינוי קוד קיים.
משתתפים בתבנית
- (ב) ,0) ,AbstractFactoryFalph: מכריז על ממשק עבור מערכת של שיטות יצירה, כל אחד מהם חוזר מוצר מופשט.
- (ב) ,0) ,ConcreteFactoryFLT:1: ליישם את שיטות הבריאה לייצר מוצרים קונקרטיים.
- (ב) ,0) ,Abstractrated ProductFLT:1: מכריז על ממשק עבור סוג של אובייקט מוצר.
- (ב) ,0) ייצור המוצר של LT:1: מגדיר אובייקט מוצר המיישם את ממשק המוצר הפשט.
- (ב) ,0) קלינטראטופול 1: משתמשים רק בממשקים שהכריזו על ידי מוצר מופשט ומוצר מופשט.
(ב) ב[[1924]], [[1924]]]], [[1924]]]]]], [[1924]]]], [[1924]]]]]], [[1924]]]]]]]]]], [[1924]]]]]]]], [[1924]]]]]]]], [[1924]]]]]]]]]]]], [[1924]]]]]]]], [[1924]]]]]]
למה קוטלין לעיבוד דפוס עיצוב?
Kotlin מביא מספר תכונות שפה מודרניות שהופכות את יישום דפוס המפעלים האבסטרקטי יותר ויותר בטוח מאשר ב- Java:
- (ב) ,0) , ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇
- (ב) ,0) שיעור הנתונים של LT:1 כדי להפחית את החתלתול במימוש המוצר.
- [01:0] הצהרות של קונסולת ה-1:0 [ה] כדי ליצור מפעלים בודדים ללא קוד נוסף.
- (ב) ,0) פונקציות סדר גבוה יותר (FLT) 1:1 להחליף ממשקי מפעל עם מפעלים של כדנדה כאשר מתאים.
- (ב) ויקרא י"א:2 ויקרא י"ד:2 ויקרא י"ד)
תכונות אלה מאפשרות לך לכתוב מערכת במפעל שאינה רק גמישה אלא גם מדליקת זמן בטוח, צמצום הצורך בבדיקות השתקפות או בריצה.
בניית מערכת זיהוי Core עם מפעל אבסטרקטי
בואו נלך דרך יישום צעד אחר צעד בקוטלין, נתחיל עם גרסה מינימלית ואז להרחיב אותו כדי להתמודד עם מורכבות בעולם האמיתי.
1.1 הגנת ממשק המוצר הפשט
כל הודעה חייבת לחשוף שיטה (FLT:5) של 5, אנו כוללים גם נכס 6 (FLT) לתמיכה בצמצום ובכניסה.
interface Notification {
val type: String
fun send(message: String): Result
}
data class Result(val success: Boolean, val error: String? = null)
2.הכנת מוצרים
באמצעות מס הסינמס של קוטלין, אנו יוצרים יישום קונקרטי עבור דואר אלקטרוני, SMS ודוחפים הודעות. עבור ריאליזם, כל יישום יכלול שיחות API בפועל, אבל כאן אנו מדמיינים אותם.
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.יצירת הממשק הפשטני
במפעל מכריז על שיטת יצירה אחת, במערכות מורכבות יותר, ייתכן שיש לך שיטות יצירה מרובות (למשל, FLT:9, FLT:10), אבל עבור מפעל פשוט אנו שומרים אותו גנרי.
interface NotificationFactory {
fun createNotification(): Notification
}
4.הפעלת מטרות
כל מפעל אחראי על מחיקת סוג מוצר אחד בדיוק.שימוש בהכרזה של ליגת ה- 12 (FLT:12) הופך את המפעל לטון, אשר לעתים קרובות מספיק.
object EmailNotificationFactory : NotificationFactory {
override fun createNotification(): Notification = EmailNotification()
}
object SmsNotificationFactory : NotificationFactory {
override fun createNotification(): Notification = SmsNotification()
}
object PushNotificationFactory : NotificationFactory {
override fun createNotification(): Notification = PushNotification()
}
השתמש בגורמים מקוד הלקוח
הלקוח (למשל, שירות הודעה) מקבל הודעה (FLT:14) ושולח הודעה ללא ידיעת מעמד המוצר קונקרטי.
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")
}
הגדרה זו כבר מדגימה את כוחה של התבנית: הוספת ערוץ חדש (למשל, Slack) דורשת רק מעמד מוצר חדש ומפעל חדש - אין שינויים בקוד הלקוחות או במפעלים הקיימים.
הקמת המערכת עם ערוצים חדשים
נניח שעלינו להוסיף הודעות Slack, אנו יוצרים את ה-FLT:16 ו- (FLT:17) שיטת ה- 18 של Slack תתקשר עם ממשק API של Slack.
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)
}
קוד הלקוח נותר בלתי נסבל.זהו סימן ההיכר של עקרון פתוח/סגור בפעולה: המערכת פתוחה להרחבה אך סגורה לשינוי.
דרישות מתקדמות לייצור-Ready Systems
בעוד התבנית הבסיסית עובדת, מערכות הודעות בעולם האמיתי דורשות תחכום יותר. בואו לחקור שיפורים באמצעות תכונות Kotlin.
מלונות ב-Exhaustive Factory Selection
במקום לעבור מפעל מופשט, תוכלו להשתמש ב- Kotlin's (FLT:20) כדי לייצג סוגי הודעות ולתת ללקוח לבחור באיזה מפעל להשתמש באמצעות ביטוי FLT:21.
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)
}
גישה זו מבטלת את ממשק המפעל נפרד ובמקום זאת משתמשת בתפקוד יחיד המחזיר את המוצר הנכון.זה פשוט יותר עבור מערכות קטנות עד בינוניות ונותן לך ביטחון בזמן.
הודעה מסונכרנת שולחת
רוב ערוצי התקשורת כוללים שיחות רשת.חזרה (FLT:23) synchronly הוא לא מעשי.
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)
}
}
}
קוד לקוחות יכול לקרוא ל-FLT:26 מתוך היקף קורטולינה:
suspend fun sendNotification(factory: NotificationFactory, message: String) {
val notification = factory.createNotification()
val result = notification.send(message)
// handle result
}
אינטגרציה
במקום מפעלים קשיחים, השתמש מסגרת הזרקת התלות כמו קובי או דגר כדי לקשור מפעלים לממשק (FLT:28 ).זה מאפשר לך להחליף את המימוש במבחנים או בתצורה.
// Koin module
val notificationModule = module {
factory<NotificationFactory>("email") { EmailNotificationFactory }
factory<NotificationFactory>("sms") { SmsNotificationFactory }
factory<NotificationFactory>("push") { PushNotificationFactory }
}
לאחר מכן קבל את המפעל הנכון מ Koin בזמן ריצה מבוסס על מפתח תצורה.
טעויות ובקשות
לעתים קרובות לא ניתן לבצע שגיאות טרנסיות.לרפא את המפעל ויצירת מוצר עם טיפול שגיאות.You יכול גם ליישם מנגנון retry באמצעות Kotlin coroutines'FLT:30 בונה.
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")
}
תבנית ואישון
הודעות לעתים קרובות דורשות templating (למשל, הודעת HTML, תוכן SMS דינמי) המפעל יכול להחזיר אובייקט הודעה כי הוא pre-configured עם מנוע תבנית.
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)
}
}
המפעל יכול ליצור גרסאות מוצר שונות בהתבסס על פרמטרים נוספים.
בדיקת מערכת ההנעה
אחד היתרונות הגדולים ביותר של דפוס המפעל המינהלי הוא מבחן.ניתן ליצור בקלות מפעלים לעג אשר מחזירים את מבחן כפול.
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)
ניתן גם לכתוב בדיקות יחידה המאמתות את המפעל מחזיר את סוג המוצר הנכון, באמצעות התאמת הסגנון של Kotlin.
« « « « « « « « « « « « « « « « « « « « « « « « « « « « « « « « « « « « « « « « « « « « « « « « « « « « « « « « « « « « « « « « « « « « « « « « « « « « « « « « « « « « « « « « « « « « « « « « « « « « « « « « « « « « « « « « « « « « « « « « « « « « « « « «
באדריכלות מיקרו-שירות, הבחירה של ערוץ הודעה עשויה לבוא מקובץ תצורה, משתנה סביבה או מסד נתונים.You יכול ליישם רישום הממפה מפתחות מיתרים למקרים של מפעל.
object NotificationFactoryRegistry {
private val factories = mutableMapOf<String, NotificationFactory>()
fun register(channel: String, factory: NotificationFactory) {
factories[channel] = factory
}
fun getFactory(channel: String): NotificationFactory? = factories[channel]
}
לאחר מכן, למפול את הרישום בסטארט-אפ של יישומים מ-FLT:36 או בדיקת מסד נתונים.זה מקטין את ההחלטה של איזה מפעל להשתמש קוד הלקוח לחלוטין.
השוואה עם שיטת המפעל
דפוס המפעל הפשטי מבולבל לעתים קרובות עם דפוס פשוט יותר של שיטת המפעל.הבדל המפתח הוא ששיטת המפעל עוסקת במוצר יחיד, בעוד המפעל האבלק עוסק במשפחות של מוצרים קשורים. במערכת ההודעות שלנו, אם היו לך מוצרים מרובים הקשורים לערוץ (למשל, מוצץ ומומחה ספציפי לערוץ זה), אתה תשתמש במפעל אבסטרקטי.עבור מוצר יחיד לתעל, שיטה (או גישה חתומה) עשוי להיות מספיק, עם קנה מידה טובה יותר, כאשר אתה צריך קיבולת גבוהה יותר, עם זאת, עם זאת, עם זאת, עם זאת, עם זאת, עם זאת, עם זאת, אם אתה צריך קיבולת של משפחות מופשטת יותר, אם אתה צריך קיבולת של קיבולת של צמחים.
שם הכל ביחד: דוגמה אמיתית לעולם
תארו לעצמכם פלטפורמה SaaS שמאפשרת למשתמשים לבחור את העדפות ההודעות שלהם: דוא"ל, SMS, דחיפה או Slack.המערכת קוראת העדפות משתמש ממסד נתונים, לבחון את המפעל המתאים (או מוזרק או הושג מרישום), ושולחת את ההודעה.שימוש בתבנית המפעל הפשט, הוספת ערוץ חדש (אומר, Microsoft Teams) פשוט דורש שיעור מוצר חדש ורישום חדש של FLT:37 - ו- תוך שימוש ב-אין שידור של השתקפות, שום הודעה, אין שינוי קוד.
// 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)
}
}
עיצוב זה אינו רק גמיש, אלא גם מאוד במבחן: ניתן ללעג למרשם ולאמת כי המפעל הנכון משמש לכל ערוץ.
Best Practices for Implementing Factory in Kotlin
- (FLT:0) כיתות חתומות על הגדרות ממשק רופפת של 1:1 כאשר מערכת המוצרים סגורה ומוכרת בעת יצירתו.זה נותן לך בדיקות ממצה.
- (ב) ,0) אובייקטים שותפים או הצהרות אובייקטים או אובייקטים להתנגדות לתקנות 1:1 עבור מפעלים שאין להם מדינה.
- (ב) פרמטר ברירת המחדל של FLT:0) פרמטר ערכים פרמטרים ברירת מחדל 1 (FLT:1) בבונים מוצרים לספק ברירת מחדל הגיונית ללא עומס יתר על המידה.
- (ב) ,0) שמור על ממשק המפעל מינימלית (FLT:1 אם אתה מוצא את עצמך מוסיף שיטות יצירה רבות, לשקול שימוש בדפוס בונה או אובייקט תצורה.
- (ב) [ה]ההתיישבות [ה] ב[[1924]], [[1924]]]], [[1924]]]], [[1924]]]], [[1924]]]]]]]], [[1924]]]]]]]], [[1924]]]]]]]]]]]]]], [[1924]]]]]]]]]]]]]], [[1924]]]]]]
- (ב) ,0) ,התחייבויות של כל מפעל ומוצרו, כי התבנית מוסיפה עקיף, שם ברור ותיעוד הם חיוניים.
משאבים חיצוניים
כדי להעמיק את ההבנה של תבנית המפעל הפשטנית ומימושה בקורלין, מתייחס למשאבים הבאים:
- (ב) ,0) ,Abstract Factory Pattern - מתן גוג'ירופל (GolruFLT) 1:1 - הסבר מקיף עם דיאגרמות UML ודוגמאות קוד.
- (ב) ,0) ,Kotlin Sealed הכיתות FLT:1, תיעוד רשמי על איך שיעורים חתומה יכולים מודל של היררכיות מעמדיות מוגבלות.
- (ב) ⁇ (ב"ב) ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇
על ידי שילוב דפוס המפעל המוכח עם תכונות השפה המודרנית של Kotlin, אתה יכול לבנות מערכת הודעה כי הוא לא רק גמיש ורחב, אבל גם בטוח ושמירה על.אם אתה תומך בשני ערוצים או עשרים, התבנית מבטיחה כי הוספת יכולות חדשות לעולם לא מרגיש כמו טקס - זה הופך להיות הרחבה צפויה, בסיכון נמוך.