본문으로 건너뛰기

เนื้อหาภาษาไทย / 태국어 콘텐츠

시스템 가이드 검수 완료된 콘텐츠

Setter Injection: อีกรูปแบบหนึ่งของ DI

บทความนี้แนะนำ Setter Injection ซึ่งเป็นรูปแบบหนึ่งของ Dependency Injection (DI) ที่ dependencies ถูกส่งเข้าไปในคลาสผ่าน Setter Methods หลังจากการสร้างออบเจ็กต์...

Setter Injection: อีกรูปแบบหนึ่งของ DI

จากบทที่แล้ว เราได้เรียนรู้เกี่ยวกับ Constructor Injection ซึ่งเป็นวิธีการส่ง Dependencies เข้าไปใน Class ผ่านทาง Constructor ในบทนี้ เราจะมาทำความรู้จักกับอีกรูปแบบหนึ่งของ Dependency Injection (DI) ที่เรียกว่า Setter Injection ซึ่งเป็นการ Inject Dependencies ผ่าน Setter Methods

ความหมายของ Setter Injection

Setter Injection คือการส่ง Dependencies เข้าไปใน Class โดยการเรียกใช้ Setter Method (method ที่ใช้สำหรับกำหนดค่าให้กับ property ของ class) หลังจากที่ Object ถูกสร้างขึ้นแล้ว แทนที่จะส่ง Dependency ผ่าน Constructor เหมือน Constructor Injection

พูดง่ายๆ คือ เราสร้าง Object ก่อน แล้วค่อย "เติม" Dependency ที่หลัง โดยใช้ Setter Method นั่นเอง

การใช้งาน Setter Injection

เพื่อให้เห็นภาพชัดเจน เรามาดูตัวอย่างการใช้งาน Setter Injection กัน

<?php

interface LoggerInterface {
    public function log(string $message): void;
}

class FileLogger implements LoggerInterface {
    private string $filePath;

    public function __construct(string $filePath) {
        $this->filePath = $filePath;
    }

    public function log(string $message): void {
        file_put_contents($this->filePath, $message . PHP_EOL, FILE_APPEND);
    }
}

class UserService {
    private LoggerInterface $logger;

    public function setLogger(LoggerInterface $logger): void {
        $this->logger = $logger;
    }

    public function createUser(string $username, string $password): void {
        // Logic ในการสร้าง User
        // ...

        // Log การสร้าง User
        $this->logger->log("User created: " . $username);
    }
}

// สร้าง Logger
$logger = new FileLogger('user_log.txt');

// สร้าง UserService
$userService = new UserService();

// Inject Logger ผ่าน Setter Method
$userService->setLogger($logger);

// ใช้งาน UserService
$userService->createUser('john.doe', 'password123');

?>

คำอธิบายโค้ด:

  • เรามี LoggerInterface และ FileLogger เหมือนกับตัวอย่างในบท Constructor Injection
  • ใน UserService เราไม่มีการ Inject LoggerInterface ใน Constructor
  • เราสร้าง Setter Method ชื่อ setLogger() เพื่อรับ LoggerInterface เข้ามา
  • เมื่อเราต้องการใช้งาน UserService เราจะสร้าง instance ของ UserService ก่อน แล้วค่อยเรียก setLogger() เพื่อ Inject LoggerInterface เข้าไป

ขั้นตอนการใช้งาน Setter Injection:

  1. สร้าง Interface หรือ Class ที่เป็น Dependency (ในตัวอย่างคือ LoggerInterface และ FileLogger)
  2. สร้าง Class ที่ต้องการ Dependency (ในตัวอย่างคือ UserService)
  3. สร้าง Setter Method ใน Class ที่ต้องการ Dependency เพื่อรับ Dependency เข้ามา (ในตัวอย่างคือ setLogger())
  4. สร้าง instance ของ Dependency (ในตัวอย่างคือ $logger = new FileLogger('user_log.txt');)
  5. สร้าง instance ของ Class ที่ต้องการ Dependency (ในตัวอย่างคือ $userService = new UserService();)
  6. เรียก Setter Method เพื่อ Inject Dependency เข้าไป (ในตัวอย่างคือ $userService->setLogger($logger);)
  7. ใช้งาน Class

ข้อดีของ Setter Injection

Setter Injection มีข้อดีหลายประการ ดังนี้:

  • Optional Dependencies: Setter Injection เหมาะสำหรับ Dependencies ที่ไม่จำเป็นต้องมีเสมอไป Class ยังสามารถทำงานได้แม้ไม่มี Dependency เหล่านั้น
  • Flexibility: สามารถเปลี่ยน Dependencies ได้ง่ายในภายหลัง โดยการเรียก Setter Method อีกครั้งด้วย Dependency ตัวใหม่
  • Lazy Loading: Dependencies สามารถถูก Inject ได้เมื่อจำเป็นต้องใช้งานจริงๆ เท่านั้น

อธิบายเพิ่มเติม:

  • Optional Dependencies: ลองนึกภาพว่า UserService อาจจะมี Logger หรือไม่มีก็ได้ ถ้าไม่มี Logger เราก็แค่ไม่เรียก `setLogger()` UserService ก็ยังทำงานได้ตามปกติ (อาจจะไม่มีการ Log)
  • Flexibility: สมมติว่าเราต้องการเปลี่ยนจาก FileLogger เป็น DatabaseLogger เราก็แค่สร้าง DatabaseLogger แล้วเรียก `setLogger()` ด้วย DatabaseLogger แทน
  • Lazy Loading: ถ้าเรามี Dependency ที่สร้าง Object ค่อนข้างนาน เราอาจจะยังไม่สร้าง Object นั้นทันทีตอนสร้าง UserService แต่รอจนกว่าจะมีการเรียกใช้งาน `createUser()` แล้วค่อย Inject Logger เข้าไป

กรณีใช้งานจริงและข้อผิดพลาดที่พบบ่อย

กรณีใช้งานจริง:

  • Caching: Inject Cache Service เข้าไปใน Class ที่ต้องการ Cache ข้อมูล โดย Cache Service อาจจะเป็น Memory Cache หรือ Redis Cache ก็ได้
  • Database Connection: Inject Database Connection เข้าไปใน Repository Class
  • Configuration: Inject Configuration Object เข้าไปใน Class ที่ต้องการอ่านค่า Configuration

ข้อผิดพลาดที่พบบ่อย:

  • ลืมเรียก Setter Method: ถ้าเราใช้ Setter Injection แล้วลืมเรียก Setter Method, Dependency จะเป็น null และอาจทำให้เกิด error ได้
  • สร้าง Setter Method ที่ไม่ถูกต้อง: Setter Method ควรรับ Dependency เป็น parameter และ assign ค่าให้กับ property ของ class เท่านั้น
  • ใช้ Setter Injection มากเกินไป: ถ้า Class มี Dependencies จำนวนมาก การใช้ Setter Injection อาจทำให้โค้ดอ่านยากและ maintain ยาก

ตัวอย่างข้อผิดพลาดและวิธีแก้ไข:

<?php

class UserService {
    private LoggerInterface $logger;

    public function createUser(string $username, string $password): void {
        // Logic ในการสร้าง User
        // ...

        // Error: Trying to call method log on null
        $this->logger->log("User created: " . $username);
    }
}

// สร้าง UserService
$userService = new UserService();

// **Error: ลืม Inject Logger**

// ใช้งาน UserService
$userService->createUser('john.doe', 'password123');

?>

วิธีแก้ไข:

<?php

class UserService {
    private LoggerInterface $logger;

    public function setLogger(LoggerInterface $logger): void {
        $this->logger = $logger;
    }

    public function createUser(string $username, string $password): void {
        // Logic ในการสร้าง User
        // ...

        // Log การสร้าง User
        $this->logger->log("User created: " . $username);
    }
}

// สร้าง Logger
$logger = new FileLogger('user_log.txt');

// สร้าง UserService
$userService = new UserService();

// Inject Logger
$userService->setLogger($logger);

// ใช้งาน UserService
$userService->createUser('john.doe', 'password123');

?>

สรุป: Setter Injection เป็นอีกทางเลือกหนึ่งในการทำ Dependency Injection ที่มีประโยชน์ในกรณีที่ Dependencies ไม่จำเป็นต้องมีเสมอไป หรือต้องการความยืดหยุ่นในการเปลี่ยน Dependencies ในภายหลัง อย่างไรก็ตาม ควรระมัดระวังในการใช้งานและหลีกเลี่ยงการใช้ Setter Injection มากเกินไป

ในบทถัดไป เราจะมาเรียนรู้เกี่ยวกับ Interface Injection ซึ่งเป็นอีกรูปแบบหนึ่งของ DI ที่ใช้ Interface ในการกำหนด Dependencies

Office.in.th Custom Service

이 구조를 바탕으로 시스템을 개발하거나 맞춤 변경하고 싶으신가요?

Office.in.th는 엔터프라이즈 웹 애플리케이션, API 연동, 공공/민간 업무 관리 시스템을 설계·개발하며 장기 지원을 제공합니다.

소프트웨어 개발 서비스 보기