- กล่าวถึงออบเจ็กต์ที่ถูกเรียกใช้แบบ instance และแบบ object เอง
- สร้าง array ของคำ โดยสร้างสมาชิกแบบ object
- การเขียน for-each และ for แบบธรรมดาเพื่อเรียกดูลายละเอียดของออบเจ็กต์
ยังแนะนำการเขียน get และ set ด้วยครับ กล่าวคือสมาชิกที่เป็น attribute ของคลาสใดๆ เราสามารถขอดูค่าหรือเปลี่ยนค่าให้ใหม่ได้ ถามว่ามีประโยชน์อย่างไรน่ะหรือ มันเป็นแนวคิดที่ต้องการให้ attribute เหล่านั้นปลอดภัยที่สุด ด้วยการระบุการเข้าถึงเป็น private ไว้ก่อน จากนั้นจงใจให้มี get หรือ set หรือทั้งสองอย่างตามแต่ผู้สร้างคลาสเห็นควรครับ หากยังไม่เข้าใจพวก public หรือ private หรือเทือกนี้ให้ข้ามไปก่อนครับ มันเป็นแง่มุมของ OOP ซึ่งตอนนี้ขอไม่กล่าวถึงละเอียดนัก
ควรทำความเข้าใจเรื่อง array ว่าประกาศอย่างไร ใช้อย่างไร หมุนลูปอย่างไร เหล่านี้อย่าให้สงสัยเป็นอันขาด ระวังเรื่องรอบในการหมุนลูป นับให้ดี เพราะโค้ดที่เกิด error บ่อยมักวนอยู่ในลูป หรือเงื่อนไขของลูปไม่ครอบคลุมงานที่อยากจะได้ครับ
สวัสดีเพื่อนๆที่รัก ณ มหาวิทยาลัยของเรามีหลักสูตรการสอนเขียนโปรแกรม Compiler ด้วยใช่ไหม ดังนั้นเรามาคุยกันว่ามันยากตรงไหน และตรงไหนที่ว่าเราจะสามารถช่วยเหลือกันได้อย่างไร ดีไหมล่ะ
โดยส่วนตัวแล้วผมรู้สึกว่าไม่ได้ยาก แม้เนื้อหาจะลึกแต่ก็มีเรื่องสนุกๆอยู่เต็มไปหมด (จริงเหรอ) จริงแท้เลยล่ะครับ เวลาที่ผมได้พบปะกับเพื่อนหลายๆคน เรื่องทฤษฎีไม่มีติดขัดกันเลย ทำได้หมดไม่ว่าจะมาแนวไหน แล้วปัญหาที่แท้จริงมันอยู่ที่ไหนล่ะ เอาเข้าจริงๆผมกลับเป็นฝ่ายที่อ่อนทฤษฎีวิชานี้อย่างแรง! ก็เลยอยากเสนอให้เรามาเขียนโปรแกรมร่วมกันครับ ใช่แล้วล่ะครับ ที่ผมจะบอกก็คือ เพื่อนๆส่วนใหญ่พื้นฐานการเขียนโปรแกรมไม่ค่อยกล้าแข็ง ผมเองก็ปีกหักหลายครั้ง กระทั่งครั้งนี้คิดว่าบินพอไหวก็เลยอยากจะแชร์และแนะแนวทางการเขียนโปรแกรมด้วยภาษา C# และ Java ประกอบการสร้างโปรแกรม Compiler นี้ครับ
ไม่รู้ว่าจะไปได้ไกลสักแค่ไหน ตอนนี้มีไฟก็ทุ่มเทไปก่อน อ่านมาถึงตอนนี้ก็อยากให้ลองดูวีดีโอที่ผมได้โพสต์ไว้ข้างต้น เนื้อหาทั้งหมดของหน้านี้สรุปได้ดังนี้ครับ
- เครื่องมือที่ใช้เขียน สำคัญมากเหมือนกันนะครับ สำหรับผู้เริ่มต้นจริงๆแล้วอาจเบื่อได้ แต่ขอให้โฟกัสเฉพาะที่ผมนำเสนอเป็นใช้ได้แล้วล่ะ
- เลือกสักภาษาหนึ่งสำหรับเริ่มต้น จะใช้ C# หรือ Java (ส่วนตัวผมแนะนำ Java อย่าถามเหตุผลเลย ส่วนตัวจริงๆ)
- บอกตัวเองให้ได้ว่า คลาส สร้างอย่างไร ประกอบไปด้วยอะไรบ้าง (เท่าที่อยู่ในวีดีโอพอ)
- จำเอาไว้ว่า คลาส คือจุดเริ่มต้นของทั้งสองภาษา คลาสที่มีเมธอด (ตอนนี้จะเรียกว่าฟังก์ชันไปก่อนก็ได้นะ) คือจุดเริ่มต้นของโปรแกรม
- สุดท้ายอย่าท้อ อย่ามะโนเอาเอง เขียน + ทำตาม เขียน + ทำตาม ทำซ้ำๆ ทำไปเรื่อยๆ จนมือหงิกก็จะเห็นผลเอง สู้ๆ
: MVP concept & Event Bus
ในที่สุดก็มาถึงหัวใจของ project นี้เสียทีกับ Model, View และ Presenter
คำถาม : เดี๋ยวๆ controller คืออะไรนะ แล้วกับ presenter นี่ยังไงเหรอ?
คำตอบ : เราทราบว่า controller จะทำ business logic กับข้อมูล โดยอาจรับมาจาก view หรือ model ก็ได้ สำหรับ web application เจ้า controller จะมีหน้าที่จัดการ URL เพิ่มด้วย (สถาปัตยกรรมของ Spring เรียก controller ลักษณะนี้ว่า front-controller) ทีนี้เจ้า presenter นี่จะอยู่ระหว่างกลาง controller กับ view ครับ จากคำถามจึงตอบได้ว่า controller นั้นติดต่อกับ view โดยตรง แต่ว่าหากมี presenter เจ้า presenter จะเข้าไปอยู่ตรงกลาง รับ input และหรือแสดง output จาก view เข้ามากระทำ business logic แทน controller อ๊ะๆ แต่ controller ไม่ได้หายไปไหนนะครับ เขาก็จะควบคุมแต่ละ presenter ที่มีความสำพันธ์ต่อกันในเรื่องนั้นๆอีกทีหนึ่ง จากภาพ controller ที่ว่าก็คือ Application Controller นั่นเอง
คำถาม : แล้ว controller แตกต่างอย่างไรกับ presenter ขอชัดๆ
คำตอบ : (-*-) ถ้าเราให้ controller เป็นส่วน business logic ของ view ฉันใด แนวคิดของ presenter นี้ก็คือ business logic ของ view ฉันนั้น
หากเป็นการ input สำหรับ MVC เจ้า input จะไปยัง controller ก่อน แต่หากเป็น MVP เจ้า input จะไปยัง presenter ก่อน
คำถาม : อะไรคือ Event Bus ในภาพ?
คำตอบ : คือกลไกประการหนึ่งที่ใช้จัดการเหตุการณ์ของ presenter กับ presenter โดยโครงสร้างข้อมูลของ event bus ก็เหมือนกับ queue
สมมติตัวอย่างง่ายๆว่า A presenter รับผิดชอบ X view และ B presenter รับผิดชอบ Y view จากนั้นต้องการแสดงผลข้อมูลที่ update แล้วไปยังส่วนแสดงผลทั้งสอง ไม่ว่า X หรือ Y view พอกดปุ่ม update ข้อมูลปุ๊บ ข้อมูลก็จะไป update ทั้งสองหน้าในเวลาแทบจะใกล้เคียงกันปั๊บ ว้าว! นี่แหละครับงานที่เกิดขึ้นโดย event bus
จงอธิบายภาพตามความเข้าใจ : จากภาพทรัพยากรจะถูกเตรียมไว้สองแห่งใหญ่ๆ หนึ่งคือที่ Application Controller (AppController) และสองคือแต่ละ View ที่ใช้เป็น UI สำหรับแสดงผล
หนึ่ง Presenter จะรับผิดชอบ business logic ของหนึ่ง View (มากกว่าหนึ่ง View ก็คงได้) โดย presenter รู้จักกับ view ผ่าน interface ที่มีชื่อว่า Display (นิยมตั้งชื่อนี้จ๊ะ) ด้วยกติกาของ interface ส่งผลให้ presenter และ view สามารถแยกกันพัฒนาได้ หรือกล่าวว่าการออกแบบ view เป็นอิสระมากขึ้น ส่งผลให้ logic design กับ UI design ไม่ผูกติดกันอีกต่อไป โหย~สุดยอดอะ
ภาพนี้อธิบายกลไกการเพิ่มลบและแก้ไขรายชื่อผู้ติดต่อ (Contact) โดยออกแบบไว้สอง presenter ได้แก่
- ContactsPresenter รับผิดชอบแสดงรายชื่อผู้ติดต่อทั้งหมด
- และ ContactEditPresenter รับผิดชอบส่วนแก้ไขชื่อผู้ติดต่อนั้นๆที่ถูกเลือก
เมื่อชื่อผู้ติดต่อถูกเลือกจากรายการฝั่ง ContactsPresenter เพื่อนำมาแก้ไข ContactEditPresenter จะมี message ไปบอกต่อ Event Bus ให้ส่ง event ไปสะกิด handler ฝั่ง ContactsPresenter การนี้ข้อมูลที่ถูกแก้ไขจากฝั่ง ContactEditPresenter ก็จะ update ในฝั่ง ContactsPresenter เป็นที่เรียบร้อย จบข่าว
ไว้เจอกันใหม่กับการทดลองทำ sample project นะครับ
อ่านเพิ่มเติม : http://www.gwtproject.org/articles/mvp-architecture.html
: Remote Procedure Calls (RPC) Code Example
จาก part ที่ 7-1 แนะนำไปแล้วสี่คลาส ได้แก่ Product bean, ProductService remote service interface, ProductServiceAsync interface และ ProductServiceImpl class implementation
คราวนี้ก็มาทำ test ง่ายๆด้วยคลาส TestBeginMVP และเรื่องหยุมหยิมของ servlet เพื่อ config พวกมันให้ทำงานร่วมกัน ดังนี้ครับ
(ดูภาพประกอบนะ ถ้าไม่เข้าใจอะ) ลอจิกของคลาส TestBeginMVP ก็คือสร้างออบเจ็กต์จาก interface โดยมี instance ชื่อว่า productServiceAsync เจ้า instance นี้เมื่อร้องขอรายการสินค้าทั้งหมดจาก getProducts ผลคือมันบังคับให้เรา implement ผลลัพธ์ต่อไปนี้ที่เป็นลักษณะของ async callback
1) onSuccess ผลสำเร็จนี้เท่านั้นผลลัพธ์จึงจะถูกส่งกลับมาแสดงผลได้
2) onFailure ล้มเหลวด้วยนานาสาเหตุ อาจเป็นที่เน็ตเวิร์คด้วยก็ได้
โดยผลลัพธ์ทั้งสองส่วนนี้มีเวลาตอบสนองไม่แน่นอน เราอาจคอยนานเป็นนาทีหรือมากกว่ากว่ามันจะบอกได้ว่า onSuccess หรือ onFailure ฉะนั้นระหว่างที่คอยเราก็ไปทำงานอื่นๆของหน้านี้ได้จ๊ะ (ถ้ามี)
ต่อมาด้านขวาของภาพคือการ config servlet แบ่งเป็นสองส่วนคือ
- servlet
- servlet-mapping
servlet เฉยๆและ servlet-mapping ต้องใช้ชื่อเดียวกัน (ดูกรอบสีส้ม) เจ้า servlet เฉยๆนี้จะบอกว่าคลาสที่เราต้องการลงทะเบียนอยู่ที่ไหนใน project ของเรา (ไล่ไปตามชื่อ package)
ส่วน servlet-mapping จะบอกว่าคลาสที่เราต้องการลงทะเบียนนั้นน่ะจะถูกเรียกด้วย URL อะไร (ตั้งมา แนะว่าเป็นตัวเล็ก) โดยใช้เครื่องหมาย / คั่นต่อจากชื่อของ project
***นิดหน่อย ใครที่ยังรันไม่ผ่านให้กลับไปดูที่ ProductService interface เพราะ GWT มีกลไกชื่อ @RemoteServiceRelativePath ซึ่งหมายความว่า หาก URL ข้างต้นส่งจากเครื่องผู้ใช้มายัง server ให้ URL นั้นมาทำงานกับ RemoteService interface ตัวนี้นะ (ก็ตัวที่เขียน @RemoteServiceRelativePath ไว้ข้างบนเนี่ย) มันก็จะสามารถจัดการคำร้องขอนั้นๆได้อย่างไรล่ะ
โอเคจบแล้วจร้า อ้อ ถ้าเกิดว่าผลลัพธ์มันออกมารกๆ (คือมีโค้ด HTML ปะปน ก็ให้ไปเปิดไฟล์ที่ชื่อ TestBeginMVP.html นะครับ (ดูกรอบสีเขียวในภาพ) จากนั้นก็ลบโค้ดในส่วนของ body ให้สะอาดตาหน่อย เป็นใช้ได้แล้วล่ะ
คราวหน้ามาดูว่าเราจะเพิ่ม MVP concept ให้กับ project นี้อย่างไร
เคเค ฝันดีครับคืนนี้
: Remote Procedure Calls (RPC) Code Example
จาก part ที่ 6 ที่ผ่านมาเราเรียนรู้แนวคิดของ RPC ไปแล้ว ตอนนี้เราก็จะเขียนโค้ดตัวอย่างเพื่อ implement แนวคิดดังกล่าวครับ
1) สร้างคลาส Product เป็น bean เก็บไว้ที่ package ชื่อ
com.sample.shred
ประกอบด้วย String name และ double price
2) สร้างตัว remote interface จากแนวคิด RPC ให้ชื่อว่า ProductService เก็บไว้ที่ package ชื่อ
com.sample.client
เขียนบริการ getProducts เพื่อขอสินค้าทั้งหมดจาก database
3) สร้าง Async (Asynchronous) interface จากแนวคิด RPC จึงชื่อว่า ProductServiceAsync เก็บไว้ที่ package ชื่อ
com.sample.client
interface นี้จะบังคับผลลัพธ์เป็น Asynchronous Callback เสมอ หมายความง่ายๆว่า ทำงานเสร็จเมื่อไรเดี๋ยวส่งผลลัพธ์กลับมาเอง ไม่ต้องคอยเค้านะจ๊ะ (ผลลัพธ์ของการ callback มีสองแบบคือ onSuccess กับ onFailure) ประมาณนั้น (เราจึงไปทำงานอื่นต่อได้ไงล่ะ)
เอาละครับฝั่ง client เตรียมเสร็จเรียบร้อย (shred คือถูกคอมไพล์ได้ทั้งสองฝั่ง) ต่อไปก็เตรียมฝั่ง server กันบ้าง
4) สร้างคลาส ที่รับเอากติกาของ ProductService มาใช้ เพื่อที่มันจะได้รู้จักคำร้องขอจากฝั่ง client คำร้องขอที่ว่าคือ getProducts นั่นเอง โดยตั้งชื่อตามแนวคิว RPC ว่า ProductServiceImpl
ที่คลาสนี้เราจะสร้างข้อมูลปลอมๆขึ้นมาก่อน (ยังไม่ต่อฐานข้อมูลจริงๆนะ มันเยอะ) แล้วก็ return กลับไปให้ฝั่ง client
ทีนี้พอ client ร้องขอ getProducts จาก server ผลลัพธ์ที่ได้จึงมีสองแบบคือ
- ได้ผลลัพธ์ onSuccess
- หรือล้มเหลว onFailure
เท่านี้ก่อนครับ ไว้ต่อ part 7-2
: Remote Procedure Calls (RPC) concept
งานของ GWT แม้นจะเป็น web app แต่ลักษณะคือ web app แบบ Desktop Application กล่าวคือได้อารมณ์การใช้โปรแกรมบน browser เสมือนใช้โปรแกรมที่ถูกติดตั้งไว้ในเครื่องคอมพิวเตอร์ส่วนบุคคล เช่น โปรแกรมสร้างเอกสารอย่าง MS Word ก็ถูกทำให้สามารถรันบน browser ได้แล้ว หรือเกมลับสมองเล็กๆตอนนี้ก็ไปวางอยู่บน browser แทบหมดสิ้น
GWT มีกลไกที่ใช้ส่งข้อมูลจากฝั่ง browser หรือ client ไปยังฝั่ง server โดยอาศัย javaScript ด้วยการ Asynchronous ครับ
การ Asynchronous ในที่นี้ก็คือการส่งข้อมูลหรือร้องขอข้อมูลจาก server โดยไม่ต้องรอผลลัพธ์กลับมาก่อน เราสามารถทำงานอื่นๆที่อยู่ในหน้านั้นต่อไปได้ (อ่านเพิ่มเติมในเรื่องของ AJAX)
ภาพนี้อธิบายได้ว่า client และ server จะติดต่อกันด้วย interface ซึ่งต้องเป็น interface ที่สืบทอดมาจาก RemoteService Interface ข้อกำหนดหรือกติกาที่เกิดขึ้นนี้แบ่งการใช้งานออกเป็นสองส่วนครับ ส่วนแรกฝั่ง client กับส่วนที่สองฝั่ง server
ส่วนแรกฝั่ง client เราจะต้องสร้าง interface ที่มีชื่อเหมือนกับลูกของ RemoteService Interface โดยเติมคำต่อท้ายชื่อไปว่า Async
จากในภาพลูกของ RemoteService ก็คือ HelloService Interface ดังนั้น interface ของเราจึงได้ชื่อว่า HelloServiceAsync
ส่วนที่สองฝั่ง server เราจะต้องสร้างคลาสที่สืบทอด RemoteServiceServlet เพื่อให้มันเข้าใจ RemoteService Interface ของฝั่ง client จากนั้นจึง implements เอาทุกๆกติกามาใช้ เพื่อให้ทาง server เข้าใจคำร้องขอหรือสามารถจัดการกับข้อมูลที่ถูกส่งมาจากฝั่ง client ได้ โดยคลาสที่ต้องสร้างนี้มักเติมคำต่อท้ายว่า Impl ครับ
มีใครคนหนึ่งถามว่า GWT เข้าใจได้อย่างไรว่า HelloServiceAsync Interface จะถูกต้องกับ HelloService Interface เพียงแค่เติมคำว่า Async ท้ายชื่อ?
คำตอบคือเจ้าสี่เหลี่ยมสีเขียวที่เขียนว่า HelloServiceProxy ด้านล่างของภาพครับ เพราะว่ามันจะถูกสร้างขึ้นมาเป็นดั่ง Proxy (หาอ่านเพิ่มเติมเรื่องแนวคิด Proxy จากในเว็บนะ) อัตโนมัติที่ implements เอาทุกๆกติกาของ HelloServiceAsync Interface มาใช้ จึงเกิดเป็นวงจรตรวจสอบระหว่าง HelloServiceAsync Interface กับ HelloService Interface แบบอ้อมไปด้วยโดยปริยาย (แต่มันมีหน้าที่สำคัญกว่านี้ ซึ่งจะไม่ขอกล่าวถึง)
สรุป RPC concept อย่างง่ายๆก็คือแนวคิดที่จะให้ฝั่ง client ติดต่อกับฝั่ง server โดยกระบวนการ RemoteService นั่นเองครับ
แนวคิดลักษณะนี้มีอยู่มากมายครับ อาจใช้วิธีการของ AJAX เพียวๆก็ได้ แต่ Google เขาคิดการ RemoteService ขึ้นมาให้ใช้ เราก็ศึกษาว่าใช้อย่างไร แล้วก็ใช้เท่านั้นเอง จบข่าว
part หน้าเราจะมาเริ่ม project ที่ใช้ RPC ขอข้อมูลจาก server มาแสดงผลที่ฝั่ง client กันนะเพื่อนๆ
: Event ถูกส่ง เราเขียน Handler มาดักจับ
จากโค้ดในรูปอธิบายได้ว่า มีปุ่มสองปุ่ม ต่างก็มีชื่อเป็นของตัวเอง ยามใดที่มันถูก Click ตัว Handler ของมันก็จะทำงานทันที
ในที่นี้ถ้าเป็นปุ่มแรกก็จะได้ message ว่า Hello World! I am Button No.1
และถ้าเป็นปุ่มที่สองก็จะได้ message ว่า Hello World! I am Button No.2
ส่วนคีย์ final ที่เติมไว้ด้านหน้าพารามิเตอร์ของเมธอด buttonOnClick นั่นก็เพื่อกำกับว่า หนึ่งปุ่มใดๆต่อหนึ่ง Handler นะ และปุ่มที่ใส่มานั้นหามเปลี่ยนการอ้างอิงเด็ดขาด
part หน้าเรามาลุย RPC concept พร้อม project ตัวอย่างกันครับเพื่อนๆ
: onClick Event กับ Alert Message
จากภาพด้านล่างประกาศการใช้คลาส Button สร้างปุ่มออกมาหนึ่งปุ่ม เขียนข้อความบนปุ่มว่า "Click" และเขียนโค้ดรอรับการกดปุ่มดังกล่าว
โค้ดที่เขียนรอรับการกดปุ่มหรือโค้ดลักษณะเขียนเพื่อรอการตอบสนองต่อเหตุการณ์ใดๆนี้เราเรียกว่า Handler ครับ พูดง่ายๆก็คือ เมื่อเกิด Event (แล้วแต่การถูกกระตุ้นให้เกิด อาจเป็นเราเองหรือระบบส่งออกมา) แล้วเราต้องการจับ Event นั้น เราก็จะเขียน Handler มาดักนั่นเอง
ในที่นี้ Handler มีชื่อว่า ClickHandler ซึ่งดักจับ Event ที่ชื่อว่า onClick ครับ
เมื่อกดปุ่ม เราก็ไปเรียก javaScript คำสั่ง Window.alert ให้แสดงข้อความตามรูป
ง่ายและสนุกดีใช่ไหมครับ ต่อไป part หน้า เราจะโมโค้ดไปดักจับ event แบบเมธอด (คล้ายใน C# : window app) กันบ้าง
: Hello World กับ onModuleLoad
จาก part ที่ผ่านมา เราลบโค้ดออกเกือบหมด คงเหลือไว้เพียง
package com.sample.client;
import com.google.gwt.core.client.EntryPoint;
public class TestBeginMVP implements EntryPoint {
@Override
public void onModuleLoad() {
}
}
จะเห็นได้ว่า ตอนนี้เรากำลังอยู่ที่ฝั่ง client (ดูจาก package) และรับเอากติกาชื่อ EntryPoint เข้ามาใช้ เพื่อกำหนดให้คลาสนี้มี onModuleLoad ซึ่งจะเป็นเมธอดแรกสำหรับเริ่มการทำงานตลอดทั้ง project
เมื่อดูจากรูป ผมเรียกใช้คลาส HTML สองครั้งเพื่อสร้างสตริง
"Hello World!" กับสตริง
"ProSbeginner or PhaiPanda"
โดยให้มันทั้งสองถูกวางไว้บน panel ที่เกิดจากคลาส VerticalPanel เสียก่อนแล้วค่อยนำมันไปวางไว้บน panel หลักที่เรียกว่า RootPanel อีกทีหนึ่ง
คำถามคือ RootPanel คืออะไร? สำคัญอย่างไร?
ตอบ RootPanel คือพื้นที่โดย default ที่เป็นตัวเริ่มต้นที่ทำหน้าที่เป็นรากฐานที่ใช้แสดง Widgets ทั้งหลาย
ลองคิดถึงจานหนึ่งใบที่ถูกกำหนดให้วางอยู่อย่างนั้น (วางไว้ที่ไหนสักแห่ง) ขอเรียกจานใบนี้ว่า จาน RootPanel ทีนี้หากเราต้องการวางจานอีกใบลงไปหรือวางสิ่งของอย่างอื่น กติกาคือเราต้องวางลงบนจาน RootPanel นี้ก่อนแล้วกองซ้อนกันขึ้นไป ไม่อย่างนั้นมันก็จะไม่แสดงผลออกมา
สิ่งที่จะวางบน RootPanel ได้ก็คือ Widget (คลาสใดๆที่ฝั่ง GWT เรียกใช้) ในตัวอย่างก็คือคลาส VerticalPanel (วางแบบแนวตั้ง) ซึ่งเราอาจเปลี่ยนเป็น HorizontalPanel (วางแบบแนวนอน) ก็ได้
อ่านเพิ่มเติมเกี่ยวกับ GWT Javadoc
http://www.gwtproject.org/javadoc/latest/allclasses-noframe.html
และ part หน้าเราจะลองใช้ปุ่มเพื่อแสดง Alert ง่ายๆกันครับ
: องค์ประกอบหลักของ Packages ของ Sample GWT Project
เมื่อเราเริ่ม project GWT เราจะพบกับ project ตัวอย่าง และเมื่อสร้างมันขึ้นมาก็จะได้ดังภาพด้านล่างนี้ครับ
ดูกรอบสีส้มเป็นหลักนะครับ ด้านซ้ายมือคือองค์ประกอบหลักซึ่งผมได้ตั้งชื่อ package ว่า com.sample ก็จะได้ package ย่อยสำคัญๆดังนี้
- com.sample.client
- com.sample.server
- com.sample.shared
com.sample.client เก็บ .java ไฟล์ทั้งหมดที่ต้องคอมไพล์ด้วย GWT compiler ได้แก่ ส่วนติดต่อผู้ใช้ (User Interface) รวมถึงแนวคิด RPC (Remote Procedure Calls) ที่ใช้กลไก asynchronous จัดการกับ Input และ Output เช่นการขอข้อมูลจาก database เป็นต้น
com.sample.server เก็บ .java ไฟล์ทั้งหมดที่ต้องคอมไพล์ด้วย Java compiler (งานหลังบ้าน) หากมีการใช้ RPC งานหลังบ้านจะต้องรู้จัก interface ที่ remote ระหว่างฝั่ง client กับ server ซึ่งจะกล่าวอย่างละเอียดในภายหลังครับ
อ่านเพิ่มเติม : http://www.gwtproject.org/doc/latest/DevGuideServerCommunication.html
com.sample.shared เก็บ .java ไฟล์ ที่สามารถถูกคอมไพล์ได้ทั้ง GWT compiler และ Java compiler เช่นพวกบีน (beans) และคลาสกลางต่างๆ (พวก utility)
ทั้งสาม package ย่อยสำคัญข้างต้นนี้ ยังสามารถถูกแบ่งย่อยเพิ่มเติมออกเป็นอีกหลายส่วน ขึ้นอยู่กับ concept ที่ใช้
ต่อไปคือทางขวาของภาพ คลาสชื่อ TestBeginMVP (ตอนนี้ยังไม่ใช้ MVP concept) มีเมธอดชื่อ onModuleLoad ทำหน้าที่เสมือน
public static void main(String[] args)
ของภาษาจาวาธรรมดานั่นแหละครับ
และเพื่อเป็นการง่ายต่อการศึกษา part หน้าเราจะลบโค้ดที่ไม่จำเป็นออกให้หมด ให้เหลือโค้ดหลักๆที่จำเป็นต่อการรันโปรแกรม ไว้เจอกันครับ ^^
ถาม : Google Web Toolkit (GWT) คืออะไร?
ตอบ : ง่ายและตรงที่สุดก็คือ เครื่องมือสำหรับสร้าง Web Application ที่เขียนด้วยภาษา Java โดยผลลัพธ์ที่ได้มาคือภาษา JavaScript (หัวใจของเรื่อง)
ทำไมจึงน่าสนใจ? เพราะ GWT สามารถจัดการปัญหาการใช้งานภาษา JavaScript กับ Browser หลากหลายยี่ห้อได้ (ในระดับดีเลยทีเดียว)
ต้องเข้าใจก่อนนะว่า ปัญหาสำคัญตอนนี้สำหรับ Dynamic Web Application คือเจ้า JavaScript ชอบงอแง กล่าวคือ (สมมติ) ทดสอบกับ IE ผลคือน่ารัก ทีนี้ทดสอบกับ Firefox ชักเหลวไหล หรือทดสอบกับ Chrome ยิ่งไปกันใหญ่ หนีออกจากบ้านไปเลย (ทำงานไม่ได้) และยิ่งกับพวกจอหลากหลายขนาดอย่าง Smart Phone หรือ Tablet ด้วยแล้ว JavaScript อย่าได้ทำงานเพี้ยนเป็นอันขาด (โม้ไปอ่านไปนะ)
ทำให้เหล่าประดานักเขียนโปรแกรมต้องมาคอยทดสอบ test งานเดียวกันกับสารพัดค่ายหลากยี่ห้อที่เป็นกลุ่มลูกค้าส่วนใหญ่ เกิดคำว่า 'เสียเวลา' กลายเป็นเรื่องเมียน้อยที่ไม่ได้ใช้เวลากับเนื้อของงาน (Business Logic) จริงๆอย่างเต็มที่ สร้างความปวดหัวและผมร่วงเป็นจำนวนมาก
เอาละในเมื่อเหลืองยืนสงบนิ่ง และแดงเตรียมจะถอย (จริงหรือเปล่า) ก็ร้อนถึงทหารต้องเข้ามาคลี่คลาย (อ่าวคนละเรื่อง) ดังนั้น Google ในฐานะแม่ใหญ่ 'รื้อค้น' จึงเป็นคนกลางจัดคิด GWT ออกมาแก้ปัญหาของภาษา JavaScript โดยชีตีลังการับประกันว่าทุก Browser ทำงานกับ JavaScript ได้ผลลัพธ์เหมือนกันหมด โอ้บระเจ้า!
โอเค ต้องเตรียมอะไรบ้าง?
ข้อ 1) ตัว IDE ช่วยเขียนเจ้าเก่าขั้นเทพ Eclipse IDE ในขณะนี้แนะนำ Eclipse Standard 4.3.1 (Eclipse 4.3 (Kepler)) ตามลิงค์ โหลดเลย
http://www.eclipse.org/downloads/
ข้อ 2) ถัดมาคือ GWT Plugin เอาไว้ให้พี่ Eclipse เขารู้จัก GWT ไง เวลา compile ก็จะได้ตามนี้ .java -> .class -> .js ซึ่งควรจะตรงกับรุ่นของพี่ Eclipse ข้างต้น (Eclipse 4.3 (Kepler)) ดังนั้นแนะนำหน้านี้ (ไม่ใช่ลิงค์โหลดนะ เดี๋ยวบอกว่าทำไง)
https://developers.google.com/eclipse/docs/download
ติดตั้งอย่างไร?
- ลองดูหน้านี้ก่อน (ยังไม่ต้องทำตาม)
http://bunyiam.com/?name=knowledge&file=readknowledge&id=2989
- จากนั้นเปิด Eclipse แล้วเลือกเมนู Help > Install New Software..
แล้วเริ่มขั้นตอนได้เลย ทำตามลิงค์ด้านบนนี้นะ เพียงเปลี่ยน URL ที่จะโหลด GWT SDKs เป็นตามเนื้อหาของข้อ 2)
- ก็จะปรากฏหน้าต่าง Available Software ตรงนี้สำคัญมาก ขั้นพื้นฐานนี้ไม่ต้องบอก Eclipse ให้โหลดมาหมดนะครับ (ซักผ้าได้หลายกะละมัง มันนานมาก) เลือกแค่
1) Google Plugin for Eclipse (required)
2) SDKs โดยโปรดเลือกย่อยลงไปอีก เอาแค่
2.1) Google Web Toolkit SDK 2.5.1
จบแล้ว... ถ้าท่านทำการนี้สำเร็จ ท่านก็จะได้ทั้ง Eclipse และ GWT SDKs เวอร์ชันล่าสุด (latest) เลยทีเดียวเทียว (ม.ค. 2014) แน่นอนว่า Eclipse ของท่านจะต้องมีไอคอนรูปตัวจี (g) สีฟ้าผุดออกมา เพื่อไว้ New Web Application Project นะครับ มิเช่นนั้นแสดงว่าหงายเงิบ
อ่านเพิ่มเติม
https://sites.google.com/site/jatupornmabangcru/google/google-web-toolkit-gwt
http://www.doesystem.com
: XML กับ Default Constructor และ Constructor
กลับมาทบกวน applicationContext.xml กันอีกครั้งก่อนจะเพิ่ม config ให้กับ constructor ของคลาส CustomerServiceImpl
คลาส CustomerServiceImpl เราได้เขียน setCustomerRepository เป็นเหตุให้ต้องเขียน setter config ที่ไฟล์ .xml เป็น
property name="customerRepository" จริงไหมล่ะ
ดูด้านล่างนี้ประกอบ (ตัดเอาบางส่วนมา และก็อย่าไปงงกับ property ref ล่ะ)
<bean name="customerService" class="com.sample.service.CustomerServiceImpl">
<property name="customerRepository" ref="customerRepository" ></property>
</bean>
จากนั้นลองกลับไปดูโค้ดจาวาที่ไฟล์ Application.java เจาะจงท่อนที่เขียนว่า
CustomerService service = applicationContext.getBean("customerService", CustomerService.class);
โค้ดข้างบนนี้ทำอะไร? มันสั่งให้ไฟล์ .xml สร้างออบเจ็กต์คลาส CustomerServiceImpl ผ่าน default constructor ครับ (default constructor หน้าตาเป็นไงคงรู้กันนะ ซึ่งเราไม่จำเป็นต้องเขียนเอง)
คำถามคือ default constructor ไม่มีพารามิเตอร์ส่งค่าให้ออบเจ็กต์ แล้วอีกท่อนที่เขียนว่า service.findAll().get(0).getFirstName() ทำงานได้อย่างไรครับ?
ใครตาไวก็จะตอบได้เลยว่ามาจาก setter config ที่เขียนบอกไว้ในไฟล์ .xml นั่นไง ถูกต้องนะครับ! หากไม่เชื่อลองลบท่อนด้านล่างนี้ออกไปสิ
<property name="customerRepository" ref="customerRepository" ></property>
ผลคือเมื่อมันพยายามเรียก findAll() ค่าที่ได้ก็จะเป็น null ทันที
สรุปได้ว่าเมื่อเราสั่งให้ไฟล์ .xml สร้างออบเจ็กต์คลาส CustomerServiceImpl ผ่าน default constructor หลังจากนั้นมันก็จะไปเรียก setter ของคลาส CustomerServiceImpl ให้ทำงานด้วย เหตุนี้มันจึงสร้างออบเจ็กต์คลาส HibernateCustomerRepositoryImpl ให้เลยโดยอัตโนมัติครับ (แท้จริงก็ตาม config ที่เขียนไว้นั่นแหละ)
ทีนี้มีบางคนเกิดอยากรู้ว่า ถ้าไม่ต้องการให้ setter ทำงานล่ะ จะมีวิธีอื่นอีกไหมในการเขียน config ในไฟล์ .xml ?
คำตอบคือ มีครับ หนึ่งในนั้นคือการเขียน constructor config ที่รับค่าออบเจ็กต์ของคลาส HibernateCustomerRepositoryImpl เข้าไปแทน ดังนี้ (ลบ setter config ออกไปได้เลย หรือจะใส่ comment ไว้ก็ได้ ในที่นี้ผมลบไปเลย)
<bean name="customerService" class="com.sample.service.CustomerServiceImpl">
<constructor-arg index="0" ref="customerRepository"></constructor-arg>
</bean>
เอาล่ะ constructor-arg index="0" คือตำแหน่งแรกของ args ตัวที่หนึ่ง
และ ref="customerRepository" ก็มีไว้อ้างไปยังคลาส HibernateCustomerRepositoryImpl ที่เขียน config ไว้ไง
เสร็จแล้ว save จะพบกับ error ทันตา นั่นเพราะคลาส CustomerServiceImpl ไม่มี constructor ดังที่เขียนไว้ใน constructor config (ส่วน default constructor ตายไปแล้วเรียบร้อย เพราะเราพยายามเขียน constructor ขึ้นมาเอง)
เราก็ต้องไปเพิ่ม constructor ลักษณะดังกล่าวให้กับคลาส CustomerServiceImpl ครับ
public class CustomerServiceImpl implements CustomerService {
...
public CustomerServiceImpl(CustomerRepository customerRepository) {
this.customerRepository = customerRepository;
}
...
}
ได้อย่างนี้แล้ว setter ในคลาสนี้ก็จะไร้ความหมายไปเลยนะ ใครอยากลองก็ comment มันออกไป แล้ว run ดูผลลัพธ์ ก็จะได้ตามเดิมครับ
ข้อสังเกตที่ผมได้รับคือ การสร้างออบเจ็กต์ด้วย xml ในกรณีตัวอย่างนี้ constructor ที่ผ่านค่าได้โดยตรงสำคัญกว่า default constructor
part ต่อไปเราจะเริ่ม injection เหล่าคลาสโดยการใช้ autowire กันนะครับ
และนี้คือโค้ดทั้งหมดของ part นี้ (ง่วงนอนแล้ว ฝันดีเพื่อนๆ)
http://www.mediafire.com/download/e75264xnp9kjbsc/spring_sample_xml_2.zip
: เตรียมลุย Spring กับ XML Setter Method
จาก part 4 และก่อนหน้านี้เราคงทราบกันแล้วว่า interface มีความสำคัญอย่างไร และในโอกาสนี้เราจะเริ่มใช้งานไฟล์ XML เพื่อเข้าถึง constructor และ set methods แทนการ new object โดยตรง
เตรียม project ให้พร้อม...
ผมเลือกใช้ IDE ที่มีชื่อว่า Spring Tool Suite (3.4.0.RELEASE) เพราะต่อไปนี้เราจะต้องอาศัยความสามารถและคุณสมบัติต่างๆของมัน (เพื่ออำนวยความสะดวกไงล่ะ) ติดตั้งให้เรียบร้อยนะ
เริ่มต้นโดยเปิด project เดิมของ part 4 (spring_sample) จากนั้น copy และ paste ให้ได้อีก project หนึ่งโดยเปลี่ยนชื่อเป็น spring_sample_xml จากนั้น close เจ้า spring_sample ไปก่อน (มันรกหูรกตา)
โหลด library ของ spring framework (เวอร์ชัน 3.2.3.RELEASE) ได้จาก
http://goo.gl/szdN1P
ซึ่งประกอบด้วย
- Sources
- Javadocs
- และ Binaries
คลาย .zip ที่ได้แล้วเปิดไปที่ [เครื่องใครเครื่องมัน]\spring-framework-3.2.3.RELEASE-dist\spring-framework-3.2.3.RELEASE\libs จะเห็น .jar เต็มไปหมด
กลับมาที่ project มองหา folder ชื่อ libs (ไม่มีให้สร้างขึ้นมา) ให้เราเลือกและ copy เจ้า library สกุล .jar (ที่คลาย .zip มากี้อะ) เข้าไปใน folder ชื่อ libs ของ project ได้แก่
- spring-beans-xxx.jar
- spring-context-xxx.jar
- spring-core-xxx.jar
- และ spring-expression-xxx.jar
โหลด library ของ Apache Commons มาด้วยจาก
http://commons.apache.org/proper/commons-logging/download_logging.cgi
มองหา commons-logging-xxx-bin.zip ในหมวดของ Binaries
คลาย .zip ที่ได้แล้วเปิดไปที่ [เครื่องใครเครื่องมัน]\commons-logging-1.1.3-bin\commons-logging-1.1.3
มองหา commons-logging-xxx.jar
กลับมาที่ project มองหา folder ชื่อ libs เดิม แล้ว copy เจ้า commons-logging-xxx.jar เข้าไปรวมกับ .jar ทั้งสี่ไฟล์ก่อนหน้านี้ (ส่วนใครสงสัยว่าแต่ละ .jar ใช้ทำอะไรบ้าง ให้ลองค้นหาเพิ่มเติมเอาเองนะก๊าบ)
สุดท้ายของการเตรียมการคือเลือก .jar ทั้งห้าไฟล์แล้วคลิกขวาเลือก Build Path ต่อด้วย Add Build Path
ผลคือได้ไฟล์กระปุกแยมมาแทน ซึ่งจะอยู่ภายใต้ Referenced Libraries ทั้งหมด
เริ่มต้นสร้าง .xml ไฟล์แรก
- คลิกขวาที่ project เลือก New ต่อด้วย Spring Bean Configuration File
- ตั้งชื่อ applicationContext.xml ในช่อง File name และเลือกที่อยู่ของมันเป็น spring_sample_xml/src แล้วจึงกดปุ่ม Finish
มันจะสร้างไฟล์ applicationContext.xml ให้ เปิดไปจะพบกับโค้ด xml ดังด้านล่าง (ไม่ต้องสนใจ แค่บอกให้รู้เฉยๆ)
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
A (วางไว้เผื่อขั้นตอนด้านล่าง)
B (วางไว้เผื่อขั้นตอนด้านล่าง)
</beans>
ณ ตำแหน่ง A แทนด้วยการบอก xml ให้รู้จักกับคลาส HibernateCustomerRepositoryImpl ซึ่งจัดว่าเป็น repository เพื่อเรียกใช้เมธอด findAll เราจึงเขียน config (บางทีเรียกว่าการลงทะเบียน) ดังนี้
<bean name="customerRepository" class="com.sample.repository.HibernateCustomerRepositoryImpl" />
โดย name คือชื่อ (อะไรก็ได้) ขณะนี้ตั้งเป็น customerRepository
ส่วน class คือแหล่งอ้างอิงตาม package เพื่อระบุยังคลาส HibernateCustomerRepositoryImpl
ณ ตำแหน่ง B เมื่อ xml รู้จักกับ repository แล้ว ก็มาถึงคราวของ service ต้องลงทะเบียนบ้าง (ถ้าสงสัยว่า repository สัมพันธ์อย่างไรกับ service ให้ย้อนไปอ่าน part ก่อนหน้านี้นะ) เขียน config ได้ดังนี้
<bean name="customerService" class="com.sample.service.CustomerServiceImpl">
<property name="customerRepository" ref="customerRepository" ></property>
</bean>
ให้สังเกตุ property name กับ property ref ให้ดีๆนะครับ (ลอง copy วางใน Notepad กล่าวคือ
- name หมายถึง set method ซึ่งยังไม่ได้เขียนขึ้น (เดี๋ยวเขียน)
- ref หมายถึง ชื่อที่อ้างไปยัง name ของ repository ข้างต้น ซึ่งก็คือ customerRepository
ทีนี้ service ก็จะรู้จักกับ repository แล้วจ๊ะ ขาดก็แค่ set method ของคลาส CustomerServiceImpl เท่านั้น ดังนั้นเปิดไฟล์ CustomerServiceImpl.java
- ยกเลิกการ new HibernateCustomerRepositoryImpl เพราะ xml ทำให้แล้ว จากนั้นเพิ่ม set method เข้าไปแทน ได้ดังนี้
package com.sample.service;
import java.util.List;
import com.sample.model.Customer;
import com.sample.repository.CustomerRepository;
import com.sample.repository.HibernateCustomerRepositoryImpl;
public class CustomerServiceImpl implements CustomerService {
/*private CustomerRepository customerRepository = new HibernateCustomerRepositoryImpl();*/
private CustomerRepository customerRepository;
public void setCustomerRepository(CustomerRepository customerRepository) {
this.customerRepository = customerRepository;
}
public List<Customer> findAll() {
return customerRepository.findAll();
}
}
เพียงเท่านี้เจ้าไฟล์ applicationContext.xml ก็จะไม่ error แล้วล่ะ
กลับไปแก้ไขการเรียกใช้ setCustomerRepository ในไฟล์ main เพื่อจะได้ run ดูผลลัพธ์ (รันตอนนี้เจอ null error แน่นอน) เปิดไฟล์ Application.java
- ยกเลิกการ new CustomerServiceImpl โดยตรง แต่จะ new ผ่าน .xml
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.sample.service.CustomerService;
public class Application {
public static void main(String[] args) {
/*CustomerService service = new CustomerServiceImpl();*/
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
CustomerService service = applicationContext.getBean("customerService", CustomerService.class);
System.out.println(service.findAll().get(0).getFirstName());
}
}
ผลการ run ก็จะได้
... mework.beans.factory.support.DefaultListableBeanFactory preInstantiateSingletons
INFO: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@4aad08: defining beans [customerRepository,customerService]; root of factory hierarchy
Phai
ดูตรงท้ายได้ Phai ออกมาก็เป็นอันว่าเรียบร้อยครับ ซึ่งต่อไปเราจะมา config ไฟล์ xml กับ constructor กันบ้าง (เยอะไปแฮะ)
ส่วนนี่คือไฟล์ที่ทำเสร็จแล้ว แนะนำให้เปิดกับ Spring Tool Suite นะครับ
http://www.mediafire.com/download/0xv59z65g65g7s1/spring_sample_xml.zip
: Model, Repository และ Service Concept
ถาม : จาก part 2 ยังมีการจำแนก package จำลองอย่างอื่นนอกจาก client กับ server อีกหรือไม่?
ตอบ : โดยหลักทั่วไปแล้ว package มักถูกสร้างขึ้นเป็นพื้นฐานเพื่อใช้เล่าเรื่องของกลุ่มคลาสใดๆอยู่แล้ว ซึ่งอยู่ที่ความคิดหรือ concept ในการสร้างคลาสต่างๆเป็นสำคัญ จากคำถามขอตอบว่ามีครับ และในที่นี้จะขอกล่าวถึง model, repository และ service เพิ่มเติมให้ด้วย
ถาม : อะไรคือ Model?
ตอบ : model ในที่นี้ก็ M ของ MVC นั่นแหละครับ (บางทีก็เรียกว่า shared) เป็น package สำหรับเก็บประดา POJO ที่จะกลายร่างเป็น Bean (ย้อนกลับไปอ่านที่ part 1 เรื่องของ POJO ถ้าจำไม่ได้นะ) เจ้า model package นี้จะเป็นตัวกลางที่ client และ server จะหยิบ bean ไปใช้ เพราะ bean นี้สำคัญมาก มันคือ data class ที่ทำหน้าที่รับหรือส่งค่าใดๆนั่นเอง
ถาม : อะไรคือ Repository?
ตอบ : concept ของ repository กว้างมาก ในที่นี้ผมหมายถึง package ที่รวบรวมคลาสที่ห่อหุ้มหรือเกี่ยวข้องกับ database เป็นหลัก
- ถ้ากล่าวถึง repository ในแง่ของคลาสที่ห่อหุ้ม Java Database Connectivity (JDBC) ไว้ก็จะเรียกให้ชัดว่า Data Access Object (DAO) หรือก็คือคลาสที่เป็นตัวกลางในการเชื่อมต่อข้อมูลระหว่างฐานข้อมูลกับส่วนอื่นของโปรแกรมของเรา ยกตัวอย่างเช่น
ส่วน server เรียกไปยัง service ทำโน่นนี่นั่นก่อน จากนั้น service เรียกไปยัง dao โดยที่ dao ยิง sql ไปกระทำกับ database อีกที และในทางกลับกันหรือหลังจากนั้น สมมติว่า dao ขอข้อมูลหนังสือทุกเล่มจาก database ได้แล้วก็จะส่งข้อมูลนี้กลับไปยัง service เพื่อทำโน่นนี่นั่น เมื่อเรียบร้อยแล้วจึงกลับไปหา server เป็นต้น
- ถ้ากล่าวถึง repository ในแง่ของคลาสที่ทำหน้าที่แทนความสำพันธ์ของฟิลด์ใน database ก็จะเรียกให้ชัดว่า Entity (แน่นอนว่าหนึ่ง entity เกี่ยวข้องกับฟิลด์ได้มากกว่าหนึ่งตาราง หรือทั้งตารางคือหนึ่ง entity ก็ได้)
ถาม : อะไรคือ Service?
ตอบ : มันคือคลาสบริการที่ server จะเรียกมาใช้งาน คลาสจำพวก service ต้องทำหน้าที่เฉพาะด้านมากๆ เช่น การเงิน, การขนส่ง, การคำนวณภาษี, การจัดการทรัพยากรบุคคล และอื่นๆ ในที่นี้ service จะเรียกใช้ repository เพื่อกระทำกับข้อมูลในรูปแบบต่างๆ แล้วส่งผลลัพธ์ในรูปของ bean กลับไปยัง server
ถาม : งั้นอะไรคือ Bean?
ตอบ : เจ้า bean ก็คือ POJO class (จาวาคลาสธรรมดา) ที่ถูกกำหนดให้มีระเบียบหรือกติกาดังนี้ต่อเติมเข้าไป
- จาวาคลาสธรรมดานั้นต้องมี default constructor เพื่อให้ประดา framework ต่างๆนำมาสร้างเป็น object ได้ง่าย
- จาวาคลาสธรรมดานั้นต้องมี accessible method หรือการเข้าถึงประเภท get, set, is (สำหรับชนิด boolean) ให้เข้าถึงคุณลักษณะ (attributes) ของมันจากภายนอก
- จาวาคลาสธรรมดานั้นควรที่จะทำ serializable ได้ เพื่อให้ประดาโปรแกรม application framework สามารถนำมันไปบันทึกหรือเรียกใช้โดย virtual machine ที่เป็นอิสระจาก platform ใดๆ
*** อ่านเพิ่มเติม https://en.wikipedia.org/wiki/JavaBeans
อย่างว่าล่ะครับ ใช้ framework ก็คือการศึกษาความคิด หรือก็คือ concept ที่เขาคิด ดังนั้นหากไม่เข้าใจความคิด ก็ยากที่จะเข้าใจ framework
และสำหรับ Spring Framework หัวใจของมันก็คือการใช้ Autowired กับ Dependency Injection (รู้แต่ว่าฉีด no config)
ไว้ต่อที่ part 4 แล้วกันนะ
ถ้าเรายังหัดเดินเหมือนๆกัน เรามาร่วมกันแชร์นะครับ
ถาม : Framework คืออะไร สำคัญอย่างไรทำไมต้องศึกษา?
ตอบ : มันคือความคิดครับ เป็นความคิดในการแก้ไขปัญหา ก็ตามแต่ framework นั้นๆจะประกาศตนเองว่าสามารถจัดการกับปัญหาอะไรได้บ้างและได้อย่างไร ก็จะมีรูปแบบหรือวิธีการที่เรียกว่า API มาให้ใช้ และเมื่อเราปฏิบัติตามแนวทางที่มันได้วางไว้ ปัญหาก็จะถูกแก้ไขในที่สุด อย่างไรก็ตามก็ต้องเลือก framework ให้ถูกกับปัญหาที่ประสบอยู่ด้วยนะครับ
ถาม : Spring Framework เหตุใดจึงน่าใช้?
ตอบ : นั้นก็เพราะว่า framework ของจาวาที่มีมาก่อนหน้านี้ (เช่น Struts เป็นต้น) ผูกพันธ์กับ Enterprise Java Bean (EJB) มากเกินไป (ผมก็ไม่เคยเขียน EJB) เข้าใจว่าเมื่อ EJB มีความสามารถมากขึ้นก็จะซับซ้อนขึ้นเรื่อยๆ (คลาสถูกถ่ายทอดหลายลำดับชั้น) ผู้สร้าง Spring ต้องการลดความซับซ้อนของ EJB จึงได้คิด Spring Framework ขึ้น (ตัดสินใจไม่เอา EJB) เขาต้องการจาวาคลาสธรรมดาอย่างที่ธรรมดาสุดๆ และเรียกจาวาคลาสธรรมดาสุดๆนั้นว่า POJO พร้อมกับบอกว่า Spring นั้น...
- Reduce the complexities of Enterprise Java development
- POJO base and Interface driven
- Lightweight and unobtrusive compared to older J2EE methodologies
- AOP / Proxiex
- Built around patterns and best practices
ถาม : Plain Old (หรือ Ordinary) Java Object (POJO) แจ่มอย่างไร?
ตอบ : ผมเป็นผู้ชายชอบผู้หญิงสวย เก่งและเริด (EJB) แต่เมื่อคบพวกเธอไปสักระยะหนึ่งแล้ว (แน่นอนว่าอาจหลายปี) ผมไม่สามารถจัดการความ art พวกเธอได้ ตรงกันข้ามเมื่อผมได้รู้จักสาวบ้านนา คนบ้านนอก (POJO) ผมบอกกับตัวเองในวินาทีนั้นว่า เธอช่าง...
- Testability
- Maintainability
- Scalability
- Complexity
- Business Focus (ตรงนี้คือจุดขายสำคัญครับ คิดแต่การแก้ปัญหาพอ เรื่องอื่นไม่อาว จะ config จะ exception ฯลฯ ไปที่อื่น ไม่ต้องเขียนอยู่หน้าเดียวกัน)
ถาม : คิดถึง Spring Framework ต้องคิดถึง MVC ใช่ไหม?
ตอบ : ใช่เกือบ 100% สำหรับงานที่ผมเห็นโดยทั่วไปเมื่อมีการกล่าวถึง Spring Framework ครับ แต่ตัวของ framework ไม่ได้สร้างเพื่อ MVC เท่านั้น เสน่ห์ของมันอยู่ที่...
- Removes configuration / lookup code
- Developers can focus on the business needs
- Code can focus on testing
- Annotation or XML base development
ดังนั้นเรานำมันมาใช้กับ application ทั่วไปได้ด้วยนะเออ มันเวิร์กก็เพราะว่า (เน้นอีกครั้ง)
- Everything is a simple POJO
- Essentially a glorified HashMap
- Can be used as a Registry
เห็นไหม ยังไม่พูดถึง MVC เลย
ถาม : ไม่เคยใช้ framework อะไรมาก่อนเลย มีแต่พื้นฐานจาวาธรรมดา จะเรียนรู้ได้อย่างไรล่ะ?
ตอบ : งั้นตามผมมาสำหรับ part 2 เรามาจำลองการใช้จาวาธรรมดาแบบมี pattern กันก่อน