วันจันทร์ที่ 12 มีนาคม พ.ศ. 2550

IOC คืออะไร

ก๊อบมาจาก http://cp27.linux.eng.chula.ac.th/index.php?act=Print&client=printer&f=13&t=1031 มันต้องล็อกอินอ่ะ

วันนี้ว่างครับ เรามาเริ่มที่ IoC กันก่อนดีกว่า 1. Introduction to Spring Frameworkบอกไว้ก่อนว่า code ทั้งหมดเป็น C#1.1 IoCก่อนจะไปดู Spring เรามาทำความเข้าใจกับ IoC ก่อน1.1.1 IoC ย่อมาจากอะไรInversion of Control1.1.2 ความหมายของ IoCความหมายตรงตัว แต่การแปลตรงตัวอาจจะยังไม่ชัดเจนเท่าที่ควร การอธิบายด้วย code ดีที่สุดครับ
CODE
public interface IA { int I { get; } IB B { get; }}public class A : IA { private int i; private IB b; public int I { get { return i; } } public IB B { get { return b; } } public A() { i = 100; b = new B1(); }}public interface IB {}public class B1 : IB {}public class B2 : IB {}
จากไอ้ code เวรข้างบน ดูเผินๆ มันก็ไม่มีอะไรที่ไม่ดี แต่ข้อจำกัดของมันคือ ไอ้ Properties ทั้งสองตัว ของ A มันถูก Hardcoded ไว้แล้ว ถ้าอยากเปลี่ยน ต้องมาแก้โค้ด ของ A อย่างเดียวเท่านั้นต่อมาเรามาดูไอ้สิ่งที่เรียกว่า IoC กัน
CODE
public class AWithIoCByConstructor : IA { private int i; private IB b; public int I { get { return i; } } public IB B { get { return b; } } public AWithIoCByConstructor() : this(100, null) { } public AWithIoCByConstructor(int i, IB b) { this.i = i; this.b = b; }}public class AWithIoCBySetter : IA { private int i; private IB b; public int I { get { return i; } internal set { i = value;} } public IB B { get { return b; } internal set { b = value;} }}public class AFactory { public IA CreateAWithIoCByConstructor() { return new AWithIoCByConstructor(100, new B1()); } public IA CreateAWithIoCBySetter() { a = new AWithIoCBySetter(); a.I = 100; a.B = new B1(); return a; }}
อย่างที่เห็นครับ ไอ้ข้างบนนี้เรียกว่า IoC คือ จะมีเมทอดอื่นมาใส่ค่าที่ต้องการให้กับตัว instance ของเรา ตัวอย่างข้างบน ใช้ FactoryMethod Pattern ไอ้ IoC (ที่กูคิดออก) มีอยู่สองแบบ คือ ใส่ค่าผ่าน Constructor กับ ผ่าน Setter ซึ่งเลือกใช้ตามความชอบจะเห็นว่า ถ้าเราอยากได้ B2 แทน B1 ก็ไม่จำเป็นต้องแก้ AWithIoC* เลย แก้ตัวFactoryแทน ภาระที่เพิ่มขึ้นก็คือต้องมาเขียน ไอ้การใส่ค่าเองแต่!!! สุดท้าย ก็ต้องมีการ แก้ code อยู่ดี กูมีทางออกง่ายๆครับ ใช้ property file เอาก็ได้ว่า เราจะใส่ค่าอะไรบ้าง วิธีนี้ทำให้ไม่ต้องแก้ code เลยครับ ส่วนนี้เป็นเรื่องของ IoC ครับ จะยังไม่พูดถึง Spring แต่จะบอกไว้ก่อนว่า Spring ก็มีวิธีคล้ายๆกันนี้ ทำให้ไม่ต้องแก้ code เลยคิดว่าตอนนี้คงเข้าใจ IoC แล้ว (และ คงเข้าใจแล้วว่า Spring ไว้ทำอะไร) ต่อไป จะพูดถึง DI1.2 DI1.2.1 DI ย่อมาจากอะไรDependency Injection1.2.2 ความหมายของ DIไอ้ DI จริงๆแล้วมันก็คือส่วนที่น่าสนใจของ IoC เนี่ยแหล่ะครับ แต่เป็นชื่อที่นิยมใช้กันมากกว่า เพราะว่า มันเห็นภาพมากกว่าไอ้ IoC ถ้าดูจากไอ้ interface IA กับ IB ใน code ของ IoC ข้างบน IB เรียกว่าเป็น Dependency ของ IA คำว่า Dependency Injection คือไอ้การ ใส่ค่าจาก เมทอด ข้างนอก นั่นเอง (โดยส่วนตัวแล้ว คำว่า DI มันเห็นภาพชัดกว่า ไอ้คำว่า IoC)จริงๆแล้วมันจะมีอีกคำ คือ Dependency Lookup (J2EE สุดสมันใช้วิธีนี้ด้วย JNDI) ซึ่งมันไม่ค่อยช่วยอะไรมาก จะไม่ขอพูดถึง1.3 Java Beanเนื่องจาก Spring Framework เริ่มต้นที่จาวา งั้นเรามารู้จักจาวาบีนเวรก่อนเนื่องจากความกระแดะของใครสักคน มันเสร่อ ตั้งชื่อไอ้คอมโพเนนท์ที่เขียนด้วยจาวาเพื่อต่อกันได้ด้วยการลากแปะ ว่า จาวาบีน แปลตรงตัวว่า เมล็ดกาแฟ ต่อจากนี้ขอเรียกว่า นัดถั่วเหตุเกิดจากการทำ dynamic binding ของ Java (ซึ่งเสร่อมาก) ทำให้ถ้าคนไม่รู้พื้นฐานอาจจะงงได้ ถ้าคนเขียน C++ มาจะรู้ว่า ตัวคนเขียนจะต้องระบุด้วยว่าจะทำ dynamic binding ของ method ไหนบ้าง ด้วยการใช้ keyword virtual ไว้เวรจาวามันเสร่อทำให้ทุก method เรยครับ (อันนี้ไม่ว่ากัน) แต่ instance varaible จะไม่มีการใส่ virtual เข้าไปให้ (คิดว่า C++ ก็ไม่สามารถใส่ virtual เข้าไปได้นะ) ทำให้ไม่สามารถทำ dynamic binding ได้ ผลก็คือ ทำ polymorhpsm ของ instance variable ไม่ได้นั่นเองไอ้ผลข้างบน ทำให้ต้องเขียน method มาใช้ในการ อ่านค่า หรือ ตั้งค่า ของ instance variable นั่นเองแต่ถ้าเขียนมั่วๆแม่งก็จะทำให้การใช้คอมโพเนนจาวาด้วยการลากแปะมันไม่เวิร์คเพราะว่า refection ไม่สามารถแยกแยะได้ว่าอันไหนเป็นเมทอดในการอ่านค่า ตั้งค่า หรือ อื่นๆ มันก็เลยตั้งคอนเวนชั่นขึ้นมา ซึ่งหลักๆก็คือ ไอ้ setter getter นั่นเองสรุปแบบง่ายๆได้ว่า นัดถั่วคือ จาวาคอมโพเนนที่สามารถทำการลากแปะในโปรแกรมที่สร้างขึ้นมาได้ (ให้คิดถึง การเขียนวินโดว์วีบีก็ได้ นะ) ซึ่งไอ้คลาสเวนจะมี ชื่อ เมทอดที่เป้น setter ว่า set แล้วตามด้วย ชื่อ instance variable มี argument เดียว กับ getter ซึ่งขึ้นต้นด้วย get แล้วตามด้วย ชื่อ instance variable ไม่มี argumentตย.public int getCount() { return count; }public void setCount(int count) { this.count = count; }1.4 Spring Frameworkหลักๆแล้วไอ้ เวร Spring Framework คือ IoC แต่มันจะมีส่วนที่เพิ่มมาด้วยคือ AOP ซึ่งน่าสนใจนิดหน่อย เมื่อเทียบกับ IoCรู้สึกว่าไอ้การพิม Spring Framework มันยาวไปหน่อย ต่อจากนี้ขอเรียกว่า ไอ้ปิง1.4.1 Spring Framework's IoCไอ้ปิงมันมี คลาสชื่อ BeanFactory มาให้ ซึ่งไอ้คลาสนี้ มันจะไปอ่านคอนฟิกไฟล์ที่เราใส่ให้มัน แล้วทำการ สร้าง factory ให้ ข้อดีที่เห็นแวบแรกคือ เราไม่ต้องเขียน FactoryMethod เองเรยดูตัวอย่างกันก่อน
CODE
XmlBeanFactory factory = new XmlBeanFactory(new FileSystemResource("a.xml"));IA a = (IA)factory.getBean("MyA");
ส่วน a.xml หน้าตาแบบนี้
CODE

ไอ้ตัวอย่างข้างบนนี้เอาไปใช้จริงไม่ได้ เพราะจริงๆแล้วไอ้ attribute class ต้องเป็น FullClassNameอธิบายวิธีใช้กันหน่อย XmlBeanFactory() เป็นคลาสที่อ่าน configure ที่เป็น xml มันจะมี Factory อื่นๆด้วย ซึ่งเลือกใช้กันเอาเอง แต่ที่สำคัญคือ getBean() ครับ สิ่งที่ใส่เข้าไปคือ alias ของ คลาสที่เราต้องการ ในที่นี้ MyA คือ AWithoutIoC ถ้าเกิดเราต้องการเปลี่ยน คลาสก็แค่มาแก้ a.xml ก็จบ ไม่ต้องแก้ code เลยตัวอย่างข้างบนนี้มันยังไม่ได้แสดงความเจ๋งของ DI นะ เป็นแค่ DL เท่านั้นอีกอย่าง ไอ้ปิงจะคิดเอาเองว่าทุก instance ของคลาสที่เราใส่ alias ให้มัน เป็น singleton ระดับ factory แปลเป็นภาษามนุษย์ว่า ในหนึ่ง BeanFactory จะมี instance ของ MyA แค่อันเดียวเท่านั้น จะ getBean() กี่รอบก็ได้ตัวเดิม ถ้าเราอยากได้แบบไม่ singleton ก็จะมี attribute ให้ใส่เพิ่มใน คราวนี้เรามาดูความเท่ของ ไอ้ปิง กับ DI ดีกว่า กูจะเปลี่ยนแค่ a.xml นะ (ขี้เกียจเขียน เพิ่ม)
CODE

จากโค้ดด้านบน เห็นชัดๆเรยว่า ถ้าอยากได้ instance ของ class A ก็แค่ขอจาก method getBean("MyA") ของ ไอ้ปิง ส่วนค่าต่างๆ ไอ้ปิงทำให้ โดยที่ไม่มีการ hardcoding เรย ถ้าเราอยากเปลี่ยนก็เปลี่ยน ค่าใน a.xml เอา (จริงๆแล้วไอ้ปิงสามารถทำ DI แบบ ผ่าน constrcutor ได้ด้วยแต่ไอ้ตัวอย่างข้างบนเป็นแบบผ่าน setter)ประโยชน์ของ DI ที่ไอ้ปิง มีให้ สามารถนำไปใช้ต่อได้กับ lib อื่นๆ เช่น J2EE Hibernate AXIS2 AspectJ และอื่นๆ(คิดไม่ออก) โดยที่ไม่จำเป็นต้องมีการเขียน code ของ ไอ้สิ่งที่นำมาใช้เรยด้วยซ้ำ นี่แหล่ะความเท่ของมัน

ไม่มีความคิดเห็น: