0Pricing
Swift Academy · บทเรียน

การฉีดผ่านตัวสร้าง

ส่งการพึ่งพาผ่านตัวเริ่มต้น

การฉีดผ่านตัวสร้าง เป็นบทเรียน Swift Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 2 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน Swift Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส Swift Academy มีบทเรียนทั้งหมด 4 บทเรียน

การฉีดผ่านตัวสร้าง

รูปแบบ DI ที่ใช้บ่อยที่สุดคือการส่งสิ่งพึ่งพาผ่านตัวเริ่มต้น อ็อบเจ็กต์จะได้รับทุกสิ่งที่ต้องใช้ตั้งแต่เวลาสร้าง และจัดเก็บสิ่งเหล่านั้นไว้

init พื้นฐาน

ประกาศพร็อพเพอร์ตีที่จัดเก็บค่า แล้วกำหนดค่าให้ใน init ผู้เรียกต้องส่งสิ่งพึ่งพาเข้ามาเพื่อสร้างอ็อบเจ็กต์

struct Greeter { func hi() -> String { "Hi" } }
struct View {
    let greeter: Greeter
    init(greeter: Greeter) { self.greeter = greeter }
    func show() { print(greeter.hi()) }
}
View(greeter: Greeter()).show()

สิ่งพึ่งพาที่เปลี่ยนแปลงไม่ได้

การใช้ let กับพร็อพเพอร์ตีที่ถูกฉีดเข้ามาทำให้พร็อพเพอร์ตีเปลี่ยนแปลงไม่ได้ ดังนั้นจึงเปลี่ยนสิ่งพึ่งพาหลังการสร้างไม่ได้

struct Engine { let hp: Int }
struct Car {
    let engine: Engine // cannot change later
    init(engine: Engine) { self.engine = engine }
}
let c = Car(engine: Engine(hp: 150))
print(c.engine.hp)

สิ่งพึ่งพาหลายรายการ

ระบุพารามิเตอร์หลายรายการเพื่อฉีดสิ่งที่ทำงานร่วมกันมากกว่าหนึ่งรายการ ตัวเริ่มต้นจะบอกข้อกำหนดทั้งหมดอย่างชัดเจน

struct DB { func get() -> Int { 7 } }
struct Cache { func put(_ v: Int) { print("cached \(v)") } }
struct Service {
    let db: DB
    let cache: Cache
    init(db: DB, cache: Cache) { self.db = db; self.cache = cache }
    func run() { cache.put(db.get()) }
}
Service(db: DB(), cache: Cache()).run()

ค่าเริ่มต้นของพารามิเตอร์

ค่าเริ่มต้นทำให้ผู้เรียกไม่ต้องระบุสิ่งพึ่งพาในระบบจริง แต่ยังสามารถแทนที่ค่าได้ในการทดสอบ

struct Logger { func log(_ m: String) { print(m) } }
struct Service {
    let logger: Logger
    init(logger: Logger = Logger()) { self.logger = logger }
    func run() { logger.log("go") }
}
Service().run() // uses default

การฉีดผ่านตัวสร้างของคลาส

คลาสใช้รูปแบบเดียวกัน ตัวเริ่มต้นจะกำหนดสิ่งพึ่งพาแต่ละรายการก่อนที่อินสแตนซ์จะพร้อมใช้งาน

class Mailer { func send() { print("sent") } }
class Signup {
    let mailer: Mailer
    init(mailer: Mailer) { self.mailer = mailer }
    func go() { mailer.send() }
}
Signup(mailer: Mailer()).go()

การฉีดค่า

สิ่งพึ่งพาไม่จำเป็นต้องเป็นอ็อบเจ็กต์ คุณสามารถฉีดค่าการกำหนดค่า เช่น URL พื้นฐานหรือแฟล็ก ด้วยวิธีเดียวกันได้

struct Client {
    let baseURL: String
    init(baseURL: String) { self.baseURL = baseURL }
    func endpoint(_ p: String) -> String { baseURL + p }
}
print(Client(baseURL: "https://api").endpoint("/users"))

จุดประกอบ

จุดหนึ่งใกล้กับจุดเริ่มต้นของ app จะเชื่อมต่อกราฟอ็อบเจ็กต์ทั้งหมด ส่วนอื่น ๆ เพียงรับสิ่งพึ่งพาที่เตรียมไว้แล้ว

struct DB { func count() -> Int { 3 } }
struct Repo { let db: DB; func n() -> Int { db.count() } }
struct App { let repo: Repo; func run() { print(repo.n()) } }
// Composition root:
let app = App(repo: Repo(db: DB()))
app.run()

หลีกเลี่ยงโกลบอลที่ซ่อนอยู่

การฉีดผ่านตัวสร้างเข้ามาแทนที่การเข้าถึงโกลบอลที่ซ่อนอยู่ สิ่งพึ่งพาแต่ละรายการจึงชัดเจน ทำให้คุณติดตามการไหลของข้อมูลได้

struct Settings { let theme: String }
struct Screen {
    let settings: Settings
    func render() { print("Theme: \(settings.theme)") }
}
Screen(settings: Settings(theme: "dark")).render()

จำเป็นกับไม่บังคับ

หากสิ่งพึ่งพาเป็นทางเลือกอย่างแท้จริง ให้จำลองด้วยชนิดทางเลือก มิฉะนั้นให้กำหนดเป็นสิ่งจำเป็น เพื่อไม่ให้อ็อบเจ็กต์อยู่ในสภาพที่กำหนดค่าไม่ครบ

struct Analytics { func track() { print("tracked") } }
struct Flow {
    let analytics: Analytics?
    func step() { analytics?.track() }
}
Flow(analytics: Analytics()).step()
Flow(analytics: nil).step()

เหตุผลที่ใช้การฉีดผ่านตัวสร้าง

วิธีนี้รับประกันว่าอ็อบเจ็กต์จะเริ่มต้นอย่างสมบูรณ์ ทำให้สิ่งพึ่งพามองเห็นได้ และทำงานร่วมกับความไม่เปลี่ยนแปลงของ let ได้ จึงเป็นค่าเริ่มต้นที่แนะนำใน Swift

struct Adder { func add(_ a: Int, _ b: Int) -> Int { a + b } }
struct Calc {
    let adder: Adder
    init(adder: Adder) { self.adder = adder }
}
print(Calc(adder: Adder()).adder.add(4, 5))

ตรวจสอบความเข้าใจ

เหตุใดจึงมักนิยมใช้การฉีดผ่านตัวสร้าง

สรุปทบทวน

การฉีดผ่านตัวสร้าง ส่งสิ่งพึ่งพาผ่าน init และจัดเก็บไว้ โดยมักใช้พร็อพเพอร์ตี let ที่เปลี่ยนแปลงไม่ได้ คุณสามารถฉีดอ็อบเจ็กต์หรือค่า ระบุค่าเริ่มต้น และเชื่อมต่อทุกอย่างที่จุดประกอบได้ บทถัดไปจะแสดงการฉีดโปรโตคอลแทนชนิดรูปธรรม

คำถามที่พบบ่อย

บทเรียน “การฉีดผ่านตัวสร้าง” ฟรีหรือไม่

ใช่ — ข้อความเต็มของ “การฉีดผ่านตัวสร้าง” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส Swift Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส Swift Academy มีบทเรียนทั้งหมด 4 บทเรียน

คุณจะเรียนรู้อะไรในบทเรียน “การฉีดผ่านตัวสร้าง”

ส่งการพึ่งพาผ่านตัวเริ่มต้น คุณปฏิบัติ Swift Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน

คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน Swift Academy หรือไม่

ไม่จำเป็นต้องมีประสบการณ์มาก่อน Swift Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 2 จากทั้งหมด 4 บทเรียน

บทเรียน “การฉีดผ่านตัวสร้าง” ใช้เวลานานแค่ไหน

บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย

ฉันเขียนและรันโค้ดในบทเรียน Swift Academy นี้ได้ไหม

ได้ บทเรียน Swift Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ

บทเรียนทั้งหมดในหลักสูตรนี้

  1. เหตุผลที่ใช้การฉีดการพึ่งพา
  2. การฉีดผ่านตัวสร้าง
  3. นามธรรมที่อิงตามโพรโทคอล
  4. การจำลองการพึ่งพาในการทดสอบ
← กลับไปที่ Swift Academy