4. Dynamic Diagram

ในหัวข้อนี้จะพูดถึงสัญลักษณ์ที่สามารถนำไปใช้ได้ใน Sequence Diagram และ Collaboration Diagram แต่จะเน้นไปที่การเขียน Sequence Diagram มากกว่า เนื่องจาก Sequence Diagram จะสามารถแปลงให้กลายเป็นโปรแกรมได้โดยตรง ดังนั้นจึงเหมาะสำหรับการนำมาออกแบบในระดับ Detailed Design จากที่กล่าวมาแล้วในหัวข้อที่แล้วเราจะพบว่า Class Diagram และ Object Diagram จะใช้คู่กันเพื่อออกแบบโครงสร้างของวัตถุที่มีอยู่ในระบบงาน แต่เนื่องจากการเราต้องการแสดงการทำงานของระบบที่ชัดเจน ดังนั้นการออกแบบแค่โครงสร้างยังไม่เพียงพอสำหรับการนำไปสร้างเป็นระบบ เรายังจำเป็นต้องใช้ Dynamic Diagram ออกแบบในส่วนของพฤติกรรมการทำงานของวัตถุที่อยู่ในระบบด้วย

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

1.    Class Scope Delegation        หมายถึง การแบ่งงานให้คลาสลูกมารับไปทำแทน ลักษณะแบบนี้เกิดขึ้นเนื่องจากที่คลาสแม่ไม่ต้องการระบุวิธีการทำงานให้ชัดเจนลงไปเนื่องจากจะทำให้ระบบมีโครงสร้างที่ไม่ยืดหยุ่นเพียงพอ จึงทิ้งงานบางอย่างที่เป็นเรื่องจำเพาะเจาะจงไว้ให้กับคลาสลูกที่มาสืบทอดต่อไป รับหน้าที่ไปทำต่อ (ดูที่ Abstract Class ในหัวข้อ 3.)

2.    Object Scope Delegation      หมายถึง การแบ่งงานให้กับวัตถุอื่นมารับไปทำแทน ส่วนใหญ่แล้วเป็นวัตถุจากคลาสอีกคลาสหนึ่งที่มีความสามารถในเรื่องนั้น ๆ ตัวอย่าง เช่นการบันทึกข้อมูลลงไปที่ฐานข้อมูลไม่ใช่ความสามารถของวัตถุ Patient ดังนั้นวัตถุ Patient จะแยกงานการบันทึกข้อมูลให้กับวัตถุ PatientDB รับผิดชอบไปทำแทน เป็นต้น บางครั้งเราเรียกคลาสที่มารับผิดชอบงานย่อย ๆ  ไปทำแทนว่าเป็น Servant Class (คลาสผู้รับใช้)

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

เมื่อเราแบ่งงานและแตกคลาสออกเป็นหลาย ๆ  คลาส ในขณะที่ระบบทำงานเราจะต้องนำคลาสเหล่านั้นมาสร้างเป็นวัตถุและสั่งให้วัตถุทำงาน เมื่อวัตถุตัวหนึ่งเริ่มทำงาน มันจะทำงานเฉพาะแต่สิ่งที่มันเชี่ยวชาญเท่านั้น เมื่อถึงจุดมันไม่เชี่ยวชาญมันจะส่งการทำงาน ต่อไปที่วัตถุอีกตัวหนึ่งที่เชี่ยวชาญกว่าในเรื่องนั้นช่วยรับงานไปทำแทน และจะมีลักษณะอย่างนี้เกิดขึ้นเป็นทอด ๆ ดังนั้นในการทำงานอย่างหนึ่ง อาจจะต้องมีวัตถุที่เกี่ยวข้องอยู่ในเส้นทางงานเป็นจำนวนมากกว่าหนึ่งตัวที่มาช่วยทำงานนั้นให้สำเร็จลุล่วง ใน Class Diagram จะไม่สามารถบอกเราได้ว่ามีวัตถุใดบ้างที่ช่วยเหลือในการทำงานอย่างใดอย่างหนึ่งให้สำเร็จ แต่เราจะต้องดูที่ Sequence Diagram เนื่องจาก Sequence Diagram จะแสดงลำดับของการสั่งงานวัตถุทุกตัวที่เกี่ยวข้องในเส้นทางงานนั้นตั้งแต่เริ่มต้นผู้สั่งงานคนแรกเริ่มต้นสั่งงานจนกระทั่งถึงวัตถุตัวสุดท้ายที่ทำงานให้

รูปภาพ 43 สัญลักษณ์ที่ใช้ใน Sequence Diagram

ในภาพที่ 43 จะเห็นว่ามีสัญลักษณ์หลายรูปที่ปรากฏอยู่ใน Sequence Diagram ซึ่งเราจะได้อธิบายถึงความหมายของสัญลักษณ์ในหัวข้อต่อไป

4.1 Message

เมื่อเราต้องการสั่งงานวัตถุให้ทำงาน เราจะเรียกว่าเป็นการส่งเมสเสจ (Message) ไปแจ้งให้วัตถุทำงานบางอย่างให้ การส่งเมสเสจเป็นภาษาทาง Object-Oriented และใน UML จะใช้เส้นลูกศรชี้จากวัตถุผู้สั่งงาน ไปที่วัตถุที่ทำงานให้

รูปภาพ 44 แสดงการส่งเมสเสจเพื่อขอให้วัตถุทำงานให้

จากภาพที่ 44 จะเห็นว่าเราเขียนเส้นโยงจากวัตถุที่เป็นผู้สั่งงานไปที่วัตถุที่ทำงานให้ เส้นนี้เราเรียกว่าเมสเสจ และเมื่อแปลงให้กลายเป็น Detailed Design เมสเสจก็คือเมธอดที่ทำโดยคลาสที่รับเมสเสจ เรามีเมสเสจอยู่ 2 แบบคือ Synchronous Message หมายถึงเมสเสจที่ผู้ส่ง ส่งไปแล้วจะต้องรอรับผลลัพธ์กลับมาทันที และ Asynchronous Message คือเมสเสจที่ผู้ส่ง ส่งไปแล้วไม่จำเป็นต้องรอรับผลลัพธ์กลับมา และทางวัตถุผู้ส่งเมสเสจหลังจากส่ง Asynchronous Message แล้วสามารถทำงานอย่างอื่นต่อไปได้เลยทันที

4.1.1 Synchronous Message

เป็นเมสเสจที่ส่งไปแล้ว ผู้ส่งต้องรอรับผลลัพธ์กลับมาด้วย ถ้าวัตถุที่รับงานไปทำยังทำงานไม่เสร็จวัตถุที่เป็นผู้ส่งไม่มีสิทธิ์ไปทำงานอื่นก่อน (Block-Waiting) ตัวอย่างของการส่งเมสเสจประเภทนี้ในชีวิตประจำวันเช่นการโทรศัพท์เวลาที่เราโทรไปเพื่อต้องการคุยกับอีกคนหนึ่ง เราจะต้องรอจนกว่าคนที่เราต้องการคุยด้วยมารับสายและระหว่างพูดคุยโทรศัพท์เราจะต้องจับจังหวะ (โดยการใช้คำว่า ฮัลโหล) อยู่กับผู้พูดที่ปลายทางตลอดเวลา

ในทางโปรแกรมการส่งเมสเสจแบบ Synchronous ก็คือการเรียกใช้เมธอดภายใน Thread เดียวกัน หรือถ้าเป็นการเรียกใช้เมธอดแบบข้าม Thread ก็จะต้องมีกระบวน Thread Synchronization เพื่อให้ Thread ผู้เรียกใช้หยุดรอจนกว่า Thread ที่ทำงานให้ (Worker Thread) ทำงานจนเสร็จก่อนแล้วจึงจะสามารถทำงานอย่างอื่นต่อไปได้

รูปภาพ 45 ตัวอย่างของเส้น Synchronous Message

ในภาพที่ 45 UML จะแสดงเส้น Synchronous Message ด้วยลูกศรหัวดำทึบ ซึ่งจะแตกต่างจากเส้นเมสเสจในภาพที่ 44 เส้นเมสเสจในภาพที่ 44 ไม่มีลูกศรหัวทึบซึ่งบอกให้ทราบว่าเป็นเส้นที่ยังไม่ได้กำหนด (Unspecify) ว่าจะให้เป็นแบบ Synchronous หรือ Asynchronous มักจะพบในขั้นตอน Conceptual Design ที่รายละเอียดของระบบงานยังไม่ชัดเจน

4.1.2 Asynchronous Message

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

หรืออาจจะเปรียบเทียบกับเมสเสจที่ส่งไปด้วยโทรศัพท์มือถือ (Short-Message) ก็เป็นลักษณะของ Asynchronous Message เช่นเดียวกัน โดยผู้ส่งเมสเสจส่งไปแล้วไม่จำเป็นต้องรอผลลัพธ์อะไร ทางฝั่งผู้รับจะรับเมสเสจไปแล้วตัดสินใจเองว่าจะทำอะไรต่อจากนั้น

รูปภาพ 46 ตัวอย่างของเส้น Asynchronous Message

จากภาพที่ 46 เราจะเห็นว่าวัตถุ Somchai ส่งจดหมายไปสั่งงานวัตถุ Somsri หลังจากนั้นแล้ววัตถุ Somchai สามารถเอาเวลาไปทำงานอย่างอื่นต่อได้ เมื่อวัตถุ Somsri รับงานมาทำจนแล้วก็จะส่งจดหมายมาบอกวัตถุ Somchai ให้ทราบว่าทำงานเสร็จแล้ว

ใน UML ใช้เครื่องหมายลูกศรสีดำครึ่งหัว เพื่อบอกให้ทราบว่าเป็นเมสเสจแบบ Asynchronous Message ดังเช่นปรากฏในภาพที่ 46

4.2 Object Life Line

เป็นเส้นประที่ลากจากข้างใต้รูปวัตถุ เพื่อบอกให้รู้ว่าวัตถุยังมีชีวิตอยู่ คำว่ามีชีวิตหมายความว่าวัตถุยังคงอยู่ในระบบสามารถใช้งานได้ ในความเป็นจริงวัตถุอาจจะไม่ได้เริ่มต้นมีขึ้นตั้งแต่ตอนที่เปิดใช้ระบบงานก็ได้ (เนื่องจากจะสิ้นเปลืองหน่วยความจำมาก ถ้าต้องค้างวัตถุทั้งหมดไว้ในหน่วยความจำของเครื่องเซิร์ฟเวอร์) แต่ในการออกแบบแล้วเราอาจจะสมมุติว่าวัตถุมีใช้งานได้ตลอดเวลาที่เปิดระบบอยู่ เราจึงเห็นว่าวัตถุส่วนใหญ่จะปรากฏอยู่ที่ด้านบนของ Sequence Diagram แล้วมีเส้น Life-Line ลากยาวลงมาจนกระทั่งบรรจบด้านล่าง

แต่อย่างไรก็ตาม มีบางกรณีที่เราต้องการเน้นย้ำให้เห็นวัตถุไม่พร้อมใช้ตั้งแต่ตอนเปิดระบบขึ้นมา แต่ก่อนจะใช้งานวัตถุได้จะต้องมีการสร้างวัตถุขึ้นก่อน ลักษณะแบบนี้แสดงไว้ในภาพที่ 47

รูปภาพ 47 ตัวอย่างของเส้นเมสเสจที่ส่งมาเพื่อสร้างวัตถุ

จากภาพที่ 47 ให้สังเกตว่าวัตถุ somchai ไม่ได้เกิดขึ้นตั้งแต่ตอนแรกที่เปิดระบบ แต่จะเกิดขึ้นเมื่อวัตถุ System สั่ง createUser ที่ตัววัตถุ UserManager และวัตถุ UserManager จะสร้างวัตถุ User ขึ้นโดยใช้ตัวแปรอ้างอิงชื่อว่า somchai หลังจากสร้างวัตถุ somchai ขึ้นแล้ว จึงเริ่มแสดงเส้น Life-Line ตั้งแต่ ณ จุดที่วัตถุถูกสร้างขึ้น

หรือบางครั้งเส้น Life-Line อาจจะขาดหายไปเมื่อวัตถุถูกทำลายทิ้งจากระบบแล้วก็ได้ เช่น ที่ปรากฏให้เห็นในภาพที่ 48

รูปภาพ 48 ตัวอย่างการใช้ Destroy Message และการตัด Life-Line ของวัตถุ

จากภาพที่ 48 จะเห็นว่าเมื่อวัตถุ UserManager สั่ง remove ไปที่วัตถุ User จะทำให้วัตถุ User ถูกทำลายทิ้งไปจากระบบ และเส้น Life-Line จะถูกกากบาทและหายไปนับตั้งแต่จุดนั้น

4.3 Activation Bar

เป็นแถบทึบที่ครอบเส้น Life-Line ไว้เป็นช่วง ๆ  ตรงบริเวณที่มี Activation Bar ครอบอยู่แสดงให้เห็นว่าวัตถุที่สั่งงานไปยังคงรอคอยผลลัพธ์กลับจากวัตถุที่ทำงานให้อยู่ ให้สังเกตในกรณีที่เป็น Asynchronous Message ในภาพที่ 46 จะเห็นว่า Activation Bar ของวัตถุ somchai จะขาดหายไปหลังจากส่งจดหมายออกไปแล้ว เนื่องจากวัตถุ somchai ไม่จำเป็นต้องรอผลลัพธ์กลับมาจากวัตถุ somsri

การเขียน Activation Bar ไว้จะช่วยทำให้เราเขียนขอบเขตของการเรียกใช้เมธอด ว่าการทำงานครอบคลุมวัตถุใดบ้าง และเมื่อวัตถุที่รับงานไปทำ ทำงานเสร็จแล้วอาจจะมีผลลัพธ์ส่งคืนกลับมา และเราจะแสดงให้เห็นเป็นเส้น return ก็ได้ (บางครั้งอาจจะไม่แสดงเส้น return ให้เห็นแต่ถ้าเป็น  Synchronous Message ผู้อ่านต้องเข้าใจอยู่แล้ว ว่าการส่งเมสเสจไปสั่งงานจะต้องรอจนทำงานเสร็จแล้วกลับออกมาจากเมธอด)

4.4 Guard

เป็นวิธีการใส่เงื่อนไขในการส่งเมสเสจ เพื่อบอกให้เข้าใจว่า เมสเสจนี้จะส่งออกไปก็ต่อเมื่อเงื่อนไขที่ใส่ไว้ใน Guard เป็นจริงเท่านั้น

รูปภาพ 49 ตัวอย่างการใช้ Guard เพื่อกำหนดเงื่อนไขก่อนสั่งงาน

จากภาพที่ 49 เราจะเห็นว่าในเมสเสจที่ 3 จะมีการ์ดเขียนไว้ว่า anUser == null หมายความว่า เงื่อนไขนี้จะต้องทดสอบแล้วเป็นจริงเสมอ จึงจะอนุญาตให้ส่งเมสเสจ new User() ต่อได้ ถ้าเงื่อนไขไม่เป็นจริง จะมีการทำงานต่อไป วิธีการเขียนการ์ดจะใส่เงื่อนไขไว้ในเครื่องหมาย [] และเมื่อเปลี่ยนให้กลายเป็นโปรแกรมแล้วการ์ดก็คือคำสั่ง if…else ในภาษาโปรแกรมทั่วไป

4.5 Code Implementation

การเขียน Sequence Diagram จะใกล้เคียงกับการเขียนโปรแกรมเชิงวัตถุมาก และ Sequence Diagram จะช่วยให้เราสามารถกำหนดได้ว่าวัตถุตัวหนึ่งสมควรจะมีเมธอดอะไรบ้าง เราจะนำเมธอดที่ได้ใน Sequence Diagram ไปเติมเต็มภาพ Class Diagram ให้สมบูรณ์ นอกจากนี้โปรแกรมเมอร์จะใช้ Sequence Diagram เป็นหลักในการเขียนโปรแกรม อย่างไรก็ตามใน Sequence Diagram ไม่ได้บอกอัลกอริทึมที่เป็นรายละเอียดปลีกย่อยภายในเมธอด (ซึ่งสมัยก่อนเราจะเขียนกันด้วย Flowchart) สำหรับรายละเอียดที่ไม่ปรากฏให้เห็นภายในเมธอดจะถือว่าเป็นส่วนที่โปรแกรมเมอร์จะต้องไปเพิ่มเติมให้สมบูรณ์ด้วยตัวเอง

ในหัวข้อนี้จะแสดงวิธีการเปลี่ยน Sequence Diagram ให้กลายเป็นโปรแกรมภาษา Java และจะช่วยให้ผู้อ่านเข้าใจวิธีการของ Sequence Diagram มากยิ่งขึ้น อย่างไรก็ตามโปรแกรมที่ได้จาก Sequence Diagram จะเป็นเพียงโครงสร้างของคลาสและเมธอดเท่านั้น รายละเอียดที่เหลือจะต้องอาศัยความรู้ในการเขียนโปรแกรมเชิงวัตถุของโปรแกรมเมอร์เองเป็นผู้ใส่เข้าไป

รูปภาพ 50 ตัวอย่างที่จะนำมาเขียนเป็นโปรแกรมภาษา Java

จากภาพที่ 50 เป็นขั้นตอนของระบบขณะที่กำลังจะสร้างผู้ใช้คนใหม่ใส่เข้าไปในระบบ โดยเริ่มจากการกรอกชื่อผู้ใช้เข้ามาผ่านทางส่วนติดต่อกับผู้ใช้ (Graphical User Interface) และส่วนติดต่อกับผู้ใช้จะมาสั่งงานวัตถุ System ให้สร้างผู้ใช้พร้อมกับส่งข้อมูลที่จำเป็นมาให้

1. โครงสร้างโค้ดของคลาส System

public class System {
    public void someMethod() {
        String id = ...;
        String user = ...;
        String password = ...;
        UserManager manager = ...;
        manager.createUser(id, user, password);
    }
}

หมายเหตุ –    เครื่องหมาย … ไม่ใช่ไวยากรณ์ของภาษา Java แต่ละไว้หมายถึงว่าไปได้ค่ามาจากที่ใดสักแห่งหนึ่งในโปรแกรม

2. โครงสร้างโค้ดของคลาส UserManager

public class UserManager {
    public void createUser(String id, String name, String password) {
        User anUser = getUser(id);
        if(anUser == null) {
            User newUser = new User(id);
            newUser.setName(name);
            newUser.setPassword(password);
            save(newUser);
        }
   }

   public User getUser(String id) {
       return ...;
   }

   public void save(User user) {
            ...
   }
}

3. โครงสร้างโค้ดของคลาส User

public class User {
    public User(String id) {
                 ...
    }

    public void setName(String name) {
             ...
    }

    public void setPassword(String password) {
            ...
   }
}

บรรณานุกรม

[Coplien 95] Coplien, James and Doug Schmidt (eds.). Pattern Languages of Program Design. Reading, MA: Addison-Wesley, 1995.

[Eriksson 98] Eriksson, Hans-Erik and Magnus Penker. UML Tookit. John Wiley & Sons, Inc. 1996.

[Gamma 95] Gamma, Erich, Richard Helm, Ralph Johson, and John Vlissides. Design Patterns. Readings, MA: Addison-Wesley, 1995.

[Coad 99] Peter Coad, Mark Mayfield. Java Design: building better apps and applets. Prentice Hall

[Coad 2000] Peter Coad, Mark Mayfield. UML in Colors. Pretice Hall

[Rose 2002] Wendy Boggs, Micheal Boggs. Mastering UML with Rational Rose 2002. Sybex

ใส่ความเห็น

อีเมลของคุณจะไม่แสดงให้คนอื่นเห็น ช่องข้อมูลจำเป็นถูกทำเครื่องหมาย *