Dagger2
จากบทความเรื่อง Dependency Injection Made Simple
ทำการอธิบายเรื่อง Dependency Injection และ Dependency Inversion Principle (DIP)
ทำให้เข้าใจว่าวิธีการนี้มีความสำคัญอย่างไรต่อการพัฒนา software

สิ่งที่น่าสนใจคือ
การจัดการ Dependency Injection ในระบบงานด้วย Dagger
ซึ่งเป็น library ที่นักพัฒนาหลาย ๆ คนไม่น่าจะพลาด
โดยเฉพาะ Android Developer น่าจะรู้จักและใช้งานกันเกือบทุกคน !!

ในบทความข้างต้นใช้ Dagger 1
แต่ในบทความนี้ใช้ Dagger 2 นะครับ

ดังนั้นเรามาดูในรายละเอียดว่ามีอะไรที่น่าสนใจบ้าง

  • Dagger 1 นั้นถูกพัฒนาและดูแลจาก Square
  • Dagger 2 นั้นถูก fork มาจาก Dagger 1 ซึ่งดูแลโดย Google

สำหรับ Android app แนะนำให้ใช้ Dagger 2 นะ

เนื่องจาก Dagger 1 นั้นมีปัญหากับ proguard
เพราะว่าใน code มีการใช้ Reflection API จำนวนมาก
และ code จะ generate ออกมาดูยากมาก ๆ
ส่วน Dagger 2 นั้นทำการแก้ไขปัญหาข้างต้นให้เรียบร้อย

ส่วนการพัฒนาระบบด้วยภาษา Java ก็ใช้งานได้เช่นกัน
ซึ่งจะอยู่ในตัวอย่างด้านล่างต่อไป

คำแนะนำสำหรับการใช้งาน Dagger 2 นั้น

ควรทำความรู้จักและเข้าใจเกี่ยวกับ Dependency Injection ก่อนนะ
มิเช่นนั้นคุณจะรู้เพียงว่า ทำแบบนี้แล้วทำงานได้
แต่ไม่ได้เข้าใจเลยว่า การทำงานเป็นอย่างไร ?
ซึ่งเป็นปัญหาอย่างหนึ่งที่มักพบเจอในการพัฒนา software !! (รู้แต่ไม่เข้าใจ)

บทความเพิ่มเติมเกี่ยวกับ Depencey Injection

อธิบาย Dependency Injection ให้เข้าใจง่าย ๆ คือ

เราจะไม่ทำการสร้าง object ของ class ที่ต้องการใช้งานเอง
ตัวอย่างเช่น

เมื่อ dependency class เริ่มมีเยอะ ๆ แล้ว
เราน่าจะมีการจัดกลุ่มและทำการสร้าง object เหล่านั้นให้เลย
ซึ่ง class นี้จะเรียกว่า Factory หรือโรงงานผลิต object นั่นเอง
ตัวอย่างเช่น

เมื่อต้องการเรียกใช้งาน dependency ต่าง ๆ ก็เรียกใช้งาน
ผ่าน Factory กันไปเลย ดังตัวอย่าง

จะเห็นได้ว่าใน Factory ต้องเขียน code แบบเดิม ๆ สำหรับ dependency ทุกตัว

มันน่าเบื่อมาก ๆ
code ซ้ำ ๆ ซาก ๆ
ดังนั้นจึงมีคนคิด library ต่าง ๆ ขึ้นมา
เพื่อลดจำนวน code ลงไป
หนึ่งในนั้นคือ Dagger
แต่ในบทความนี้จะเน้นไปที่ Dagger 2

เริ่มด้วยการใช้งาน @Inject สำหรับ Dependency Injection กัน มีอยู่ 3 แบบ คือ

  • Constructor Injection
  • Field Injection
  • Method Injection

ตัวอย่างเช่น

ปัญหาต่อมาคือ แล้วจะไปเอา Object ของ Dependency มาจากไหนล่ะ ?

ในตัวอย่างแรกมี Factory class สำหรับเตรียมและสร้าง object ต่าง ๆ
เมื่อมาใช้ Dagger 2 แล้วก็ต้องจัดการเช่นกัน
ซึ่งจะใช้งานผ่าน Module และ Component

โดยโครงสร้างของ dependency ต่าง ๆ ถูกนำเสนอในรูปแบบของ graph
ที่เป็นแบบ Directed Acyclic Graph (DAG)
มันคือ directed graph ที่ไม่เกิด cyclic นั่นเอง
ซึ่งเป็นที่มาของชื่อ Dagger นั่นเอง
แสดงดังรูป

AcyclicDigraphs_800
มาดูรายละเอียดของทั้งคู่กันนิดหน่อย

Module คือ Factory นั่นเอง

สามารถแบ่ง dependency ต่าง ๆ ออกเป็นกลุ่ม
เพื่อให้ง่ายต่อการจัดการและใช้งาน
รวมทั้งเชื่อมโยง dependency ต่าง ๆ เข้าด้วยกัน
แถมสามารถอ้างอิงไปยัง Module อื่น ๆ ได้อีก
ตัวอย่างเช่น

Component คือ ประตูหรือทางเข้าใช้งาน

สิ่งต่าง ๆ ที่กำหนดไว้ผ่าน annotation @Injection และ @Provides
เทียบง่าย ๆ ก็คือ interface นั่นเอง

ซึ่ง interface ไม่สามารถสร้าง object ได้
ดังนั้น Dagger 2 จึงทำการสร้าง class มาให้ใช้งาน
มีรูปแบบชื่อ class ดังนี้ DaggerComponentName
ตัวอย่างเช่น

จากนั้นให้ทำการ run ด้วยคำสั่ง

mvn clean install  exec:java -Dexec.mainClass="demo.di.Main"

จากตัวอย่างจะเห็นว่าเมื่อนำแนวคิด Dependency Injection มาใช้แล้ว

ทั้ง class MyClass, Dependency1 และ Dependency2 นั้น
แยกการทำงานออกจากกันชัดเจนมาก (Loose coupling)
ทำให้แต่ละส่วนทำงานเป็นอิสระมากขึ้น
ทำให้จัดการได้ง่ายและสะดวกขึ้น
ทำให้ทดสอบได้ง่ายขึ้น

แต่ปัญหาที่ตามมาและหลีกเลี่ยงไม่ได้คือ
ความซับซ้อนที่สูงขึ้น
จำนวน class/interface มากขึ้น
ระบบงานเริ่มมี magic มากขึ้น
ทำให้ learning curve สูงขึ้น

ดังนั้นก่อนจะเริ่มใช้งานอะไร
ขอแนะนำให้ศึกษาเรื่องพื้นฐานก่อนเสมอ
อย่าใช้เพียงเพราะว่าเขาบอกว่า ฟังมาว่า มันดี !!

สามารถดู source code ของตัวอย่างได้จาก Github::MyDagger2
และสามารถดูตัวอย่าง code เพิ่มเติมเรื่องการชงกาแฟ
เป็นตัวอย่างจาก Dagger 2 :: Coffee
อธิบายได้ชัดเจนมาก

โดยแสดงการทำงานดังรูป

dagger-example

ในบทความต่อไปจะเป็นตัวอย่างในการพัฒนา Android app
มีส่วนการทำงานหรือ dependency ต่าง ๆ เยอะมาก
ทั้ง Activity, Fragment, Service รวมทั้ง 3-parties library ต่าง ๆ อีก
มาดูกันว่าสามารถจัดการด้วย Dagger 2 กันอย่างไร