Fabrika Kalıbı
Coddy'nin Kotlin Journey'sinin Nesne Yönelimli Programlama bölümünün bir parçası. Ders 43 / 57.
Fabrika deseni, hangi sınıfın oluşturulacağına ilişkin kararı tek bir yerde toplar. Çağıran, neye ihtiyaç duyduğunu belirtir ve somut bir sınıfın adını vermeden arayüz türünü alır:
interface Notifier {
fun send(to: String): String
}
class EmailNotifier : Notifier {
override fun send(to: String) = "email to $to"
}
class SmsNotifier : Notifier {
override fun send(to: String) = "sms to $to"
}
object NotifierFactory {
fun create(channel: String): Notifier? = when (channel) {
"email" -> EmailNotifier()
"sms" -> SmsNotifier()
else -> null
}
}main içinde:
println(NotifierFactory.create("sms")?.send("ada"))
println(NotifierFactory.create("fax")?.send("bo"))Çıktı:
sms to ada
nullKotlin'de bir factory çoğunlukla interface'in veya base class'ın companion object'i içindeki bir işlevdir; bu nedenle çağıranlar Shape.from("circle 2") yazar. Herhangi bir şey oluşturmadan önce girdiyi ayrıştırıp kontrol edebilir:
interface Shape {
fun area(): Double
companion object {
fun from(text: String): Shape? {
val p = text.split(" ")
val n = p.getOrNull(1)?.toDoubleOrNull() ?: return null
return when (p[0]) {
"circle" -> Circle(n)
"square" -> Square(n)
else -> null
}
}
}
}
class Circle(val r: Double) : Shape {
override fun area() = 3.14 * r * r
}
class Square(val s: Double) : Shape {
override fun area() = s * s
}main içinde:
println(Shape.from("square 3")?.area())
println(Shape.from("circle x")?.area())Çıktı:
9.0
nullÇağıranlar yalnızca arayüzü görür; bu nedenle fabrika, onlara dokunmadan döndürdüğü sınıfı değiştirebilir. Burada küçük veriler bellekte tutulur, büyük veriler ise diske yazılır:
interface Storage {
fun describe(): String
}
class MemoryStorage : Storage {
override fun describe() = "memory"
}
class DiskStorage(val path: String) : Storage {
override fun describe() = "disk at $path"
}
fun storageFor(sizeMb: Int): Storage = if (sizeMb < 100) MemoryStorage() else DiskStorage("/tmp/cache")main içinde:
println(storageFor(5).describe())
println(storageFor(500).describe())Çıktı:
memory
disk at /tmp/cacheBir fabrika aynı zamanda bir değer olabilir: (String) -> Animal türündeki bir işlev, çağıran kişi sınıflarını bilmeden nesneler oluşturur. Adlardan bu tür işlevlere eşleme yapan bir map bir kayıt defteridir ve ::Dog gibi bir kurucu referansı hazır bir fabrika işlevidir:
open class Animal(val name: String) {
open fun sound() = "..."
}
class Dog(name: String) : Animal(name) {
override fun sound() = "Woof"
}
class Cat(name: String) : Animal(name) {
override fun sound() = "Meow"
}main içinde:
val makers: Map<String, (String) -> Animal> = mapOf("dog" to ::Dog, "cat" to ::Cat)
val pet = makers.getValue("cat")("Tom")
println("${pet.name} says ${pet.sound()}")Çıktı:
Tom says MeowGörev
KolaySağlanan Exporter arayüzünü (extension ve export(title, lines)) birkaç dışa aktarıcı uygular. MarkdownExporter (md uzantısı: bir # Title satırı ve her satır için bir - item satırı), CsvExporter (csv uzantısı: title,Title ve ardından her satır için line,item) ve PlainExporter (txt uzantısı: başlık büyük harflerle, ardından satırlar değiştirilmeden) sınıflarını yazın. Ardından fabrika nesnesi ExporterFactory'yi yazın: create(format), büyük/küçük harf durumunu göz ardı ederek markdown, csv veya plain için dışa aktarıcıyı ya da null değerini döndürür; supported() ise biçim adlarını döndürür.
Sağlanan kod bir biçim, bir başlık ve satırları okur ve report.md ile dışa aktarılan metni veya unsupported format pdf; try markdown, csv, plain ifadesini yazdırır.
Kodunuz MarkdownExporter.kt, CsvExporter.kt, PlainExporter.kt, ExporterFactory.kt ve Exporter.kt dosyalarına gider. Main.kt, sağlanan girdi/çıktı kodunu içerir ve düzenlenemez.
Kendin dene
fun main() {
// Sağlanan girdi/çıktı kodu: olduğu gibi bırakın
val input = generateSequence(::readLine).toList()
val exporter = ExporterFactory.create(input[0])
if (exporter == null) {
println("unsupported format ${input[0]}; try ${ExporterFactory.supported().joinToString(", ")}")
} else {
println("report.${exporter.extension}")
println(exporter.export(input[1], input.drop(2)))
}
}
Bu ders kısa bir quiz içerir. Soruları yanıtlamak ve ilerlemeni kaydetmek için derse başla.
Nesne Yönelimli Programlama bölümündeki tüm dersler
1Sınıflar ve Nesneler
Dosyalarla ÇalışmaSınıfları TanımlamaBirincil Yapıcılarinit Blokları ve Doğrulamaİkincil YapıcılarTekrar - Kütüphane Kartı4Kalıtım
Açık Sınıflar ve Alt SınıflarÜyeleri Geçersiz Kılmasuper ve YapıcılarSoyut SınıflarTekrar - Personel Dizini2Özellikler ve Kapsülleme
Özel ErişimcilerGörünürlük DeğiştiricileriÖzel Setter'larlazy ve lateinitTekrar - Banka Hesabı5Arayüzler
Arayüz BildirimleriVarsayılan MetotlarBirden Çok ArayüzTür Olarak ArayüzlerÖzet - Ödeme Yöntemleri8Generic'ler
Generic FonksiyonlarGeneric SınıflarTür Kısıtlamalarıin ve out ile VaryansTekrar - Öncelik Kuyruğu11Proje: Kütüphane Yönetimi
Kitaplar ve ÜyelerKitap Ödünç AlmaKendi başına pratik yap: Kotlin playground