Singleton design pattern
Jan 18th
Singleton design pattern รูปแบบการออกแบบ class ในความต้องการที่ว่า เราอยาก ให้มีการสร้าง instance ของ class เพียง instance เดียวตลอดการทำงานของโปรแกรม ซึ่งผู้เรียกใช้สามารถเข้าถึงได้ผ่านทาง global access point หรือจุดที่เข้าถึง ที่เป็น global
สำหรับตัวอย่างการใช้งานของ pattern นี่นั้นเรามักจะใช้กับ ส่วนที่ต้องการให้มีเพียงหนึ่งเดียว เช่น file system หรือ windows manager เป็นต้น
โครงส้รางของ Singleton design pattern
จากโครงส้รางของ singleton design pattern เราจะเห็นว่า class ที่เป็น singleton นั้นเราจะให้มีการ ส้ราง instance ของตัวเอง ผ่านทาง Method ที่ชื่อว่า Instance() เพื่อให้เข้าใจง่ายขึ้นเราลองมาดูที่ code ตัวอย่างกันครับ
// Singleton class implements that simplest version of the Singleton
// design pattern.
//
public sealed class Singleton
{
private static readonly Singleton _instance = new Singleton();
// make the default constructor private, so that no can directly create it.
private Singleton()
{
}
// public property that can only get the single instance of this class.
public static Singleton Instance
{
get
{
return _instance;
}
}
}
<< ตัวอย่าง code จาก Design Pattern: Singleton in C# เขียนโดย Pedro Silva (darthpedro99@hotmail.com) >>
จาก code เราจะเห็นว่า class นั้นจะถูกกำหนด ให้เป็น seal class ก็คือจะไม่ได้มีการ inmplement class หรือ สืบทอด class นี้ ต่อไปเราจะพบว่า ตัวแปรที่ชื่อว่า instance นั้นเป็นตัวแปรที่ ชี้ไปยัง instance ของ class ครับ และมันถูกกำหนดให้เป็น stactic ทำให้มัน ถูกสร้างขึ้นมาครั้งเดียว หรือ instance เดียว เมื่อมีการ access ครั้งแรกเท่านั้น สำหรับการ access ครั้งต่อไป มันก็จะ ให้ instance เดิมครับ และมันถูกกำหนดให้เป็น readonly ไม่สามารถเปลี่ยนหรือแก้ไข ใด ๆ นะครับ
อีกอย่างที่สำคัญคือ หากต้องการที่จะได้ instance ของ class นี้นั้นจะต้อง access ผ่านทาง properties (หรือ method ) ที่ชื่อว่า Instance ซึ่งเป็นจุดเดียวที่ อนุญาติให้เข้าถึง instance ของ object นี้
ลองมาดูตัวอย่าง การใช้งานจริงกัน นะครับ
// singleton class
//----------------------------------------------
public sealed class LoadBalancer
{
private static readonly LoadBalancer _instance;
private List<string> _servers = new List<string>();
private Random _random = new Random();
// Lock synchronization object
private static object syncLock = new object();
// Constructor (protected)
protected LoadBalancer()
{
// List of available servers
_servers.Add("ServerI");
_servers.Add("ServerII");
_servers.Add("ServerIII");
_servers.Add("ServerIV");
_servers.Add("ServerV");
}
public static LoadBalancer GetLoadBalancer()
{
// Support multithreaded applications through
// 'Double checked locking' pattern which (once
// the instance exists) avoids locking each
// time the method is invoked
if (_instance == null)
{
lock (syncLock)
{
if (_instance == null)
{
_instance = new LoadBalancer();
}
}
}
return _instance;
}
// Simple, but effective random load balancer
public string Server
{
get
{
int r = _random.Next(_servers.Count);
return _servers[r].ToString();
}
}
}
เป็น class สำหรับ ทำ random เพื่อจ่ายการทำงาน ให้กับ server โดย instance ของ class จะ access ได้ผ่านท่าง GetLoadBalancer() ครับ
ข้อสังเกตุ นะครับ สำหรับการใส่ lock(syncLock) ไว้ก่อนการสร้าง instance เป็นการ ทำเพื่อให้สามารถนำ code นี้ไปใช้ในกรณี ที่มีหลาย thread ครับ
ดูตัวอย่างของการใช้ class นี่นะครับ
class MainApp
{
// <summary>
// Entry point into console application.
// </summary>
static void Main()
{
LoadBalancer b1 = LoadBalancer.GetLoadBalancer();
LoadBalancer b2 = LoadBalancer.GetLoadBalancer();
LoadBalancer b3 = LoadBalancer.GetLoadBalancer();
LoadBalancer b4 = LoadBalancer.GetLoadBalancer();
// Same instance?
if (b1 == b2 &amp;amp;amp;amp;&amp;amp;amp;amp; b2 == b3 &amp;amp;amp;amp;&amp;amp;amp;amp; b3 == b4)
{
Console.WriteLine("Same instance\n");
}
// Load balance 15 server requests
LoadBalancer balancer = LoadBalancer.GetLoadBalancer();
for (int i = 0; i < 15; i++)
{
string server = balancer.Server;
Console.WriteLine("Dispatch Request to: " + server);
}
// Wait for user
Console.ReadKey();
}
}
จะเห็น ว่าการเรียกใช้ เรานะทดสอบ การทำงานของ class ด้วยการส้ราง LoadBalance b1 , b2, b3, b4 เพื่อทดสอบว่า ทั้งหมดเป็น instance เดียวกัน
instance ของ class LoadBalancer จะถูกสร้าง ครั้งแรกครั้งเดียว เมื่อเรากำหนดค่าให้กับ b1
ในส่วนที่สองเป็นการ ทดสอบว่า มีการจ่ายงานให้กับ server หรือไม่อย่างไร
คงพอเข้าใจนะครับ เป็น การสร้างและทดสอบ การทำงาน singleton design pattern
คงพอที่ได้ แนวคิดในการใช้งาน นะครับ สำหรับ thread safe นั้นหากต้องการดูเพิ่มเติม ได้ที่ Design Pattern: Singleton in C#
ธีระพงษ์ สนธยามาลย์ Soft Speed Solution ’s senior programmer s_teearpong2000@yahoo.com
Factory Method Design Pattern
Jan 18th
Factory pattern เป็น design pattern ที่จะสร้าง instance ของ class ที่ต้องการ ตามข้อมูลที่กำหนดให้ไป หรือผู้ใช้เป็นผู้เลือกว่าจะ ส้ราง object ใด และ class เหล่านี้ที่ ถูกสร้างขึ้นนั้นมักจะ มี parent ร่วมกัน และก็มี method บางส่วนเหมือนกัน แต่ จะทำงานต่างกันออกไป
โครงสร้างของ Factory pattern

จากโครงสร้าง จะเห็นว่า เราจะมี abstract class ที่ชื่อว่า Product และมี child เป็น ProductB และ ProductA ซึ่งทั้งสอง class นี้ได้ทำการ implement Product แต่เราจะไม่สร้าง object ของทั้งสอง class นี้โดยตรงนะครับ
เราจะสร้าง object ของ สอง class นี้ผ่านทาง CreateProduction(int spec) method ของ ProductFactory class โดยที่ parameter spec นั้นเป็นตัวที่จะบอกกับ Createproduction(int spec) ว่าเราต้องการสร้าง object ของ ProductB หรือ ProductA นั่นเอง เป็นไงครับพอจะเข้าใจไหมครับ
ตัวอย่างของการนำไปใช้กันบ้าง
ตัวอย่างที่เห็นชัดเจน หากเราเคยใช้งาน หรือเคยทดลองใช้ Enterprise Library ของ Microsoft เราจะพบว่า ได้มีการประยุกต์ใช้ factory pattern เช่น ใน Data Access Application Block ของ Enterprise Library.
ใน Data Access Application block นั้นมี class ที่ชื่อว่า Database ( Product class ) ซึ่งเป็น base class ให้กับ SqlDatabase และ OracleDatabase classed ( ProductA, ProductB ) และ factory class ก็คือ CreateDataBase(string name) ( Createproduct(spec))
CreateDatabase method นั้นทำหน้าที่ สร้าง instance ของ Database ชนิดที่ต้องการ ซึ่ง อาจเป็น SqlDatabase หรือ OracleDatabase ขึ้นอยู่กับ ค่าที่ส่งผ่าน parameter ที่ชื่อ name
สิ่งที่เราจะสังเกตเห็นก็คือ ว่า CreateDatabase เป็น static method นะครับ
ตัวอย่างการใช้งาน
interface IPizza
{
double getPrice();
}
abstract class Pizza : IPizza
{
public abstract double getPrice();
}
class HamAndMushroomPizza : Pizza {
override
public double getPrice() {
return 8.5;
}
}
class DeluxePizza : Pizza {
override
public double getPrice() {
return 10.5;
}
}
class HawaiianPizza : Pizza {
override
public double getPrice() {
return 11.5;
}
}
class PizzaFactory {
public enum PizzaType {
HamMushroom,
Deluxe,
Hawaiian
}
public static IPizza createPizza(PizzaType pizzaType) {
switch (pizzaType) {
case PizzaType.HamMushroom:
return new HamAndMushroomPizza();
case PizzaType.Deluxe:
return new DeluxePizza();
case PizzaType.Hawaiian:
return new HawaiianPizza();
}
throw new ArgumentException("The pizza type " + pizzaType + " is not recognized.");
}
}
class PizzaLover {
public static void Main (string[] args) {
PizzaFactory.PizzaType[] pizzaTypes = { PizzaFactory.PizzaType.HamMushroom,
PizzaFactory.PizzaType.Deluxe,
PizzaFactory.PizzaType.Hawaiian};
foreach (PizzaFactory.PizzaType pizzaType in pizzaTypes) {
System.Console.WriteLine("Price of " + pizzaType + " is " +
PizzaFactory.createPizza(pizzaType).getPrice());
}
}
}
ครับคงพอได้ concept นะครับ
teerapong sontayaman senior programmer , Soft Speed Solution , s_teerapong2000@yahoo.com
รู้จักกับ Design Patterns
Jan 4th
โปรแกรมเมอร์ หรือ ผู้ที่อยู่ในวงการการพัฒนาโปรแกรม จะรู้จักกับคำว่า design pattern ไม่มากก็น้อย หลายคนก็รู้จักดี เพราะใช้งานอยู่ หลายคน ก็เรียนรู้มาในหลักสูตร แต่ก็ไม่เคยที่จะคิดใช้ หรือ ไม่ก็ไม่รู้ว่าจะใช้อย่างไรตอนไหน ซึ่งระหว่าเรียนก็ไม่เคยได้เห็น การนำไปใช้จริง หรือบางคนก็เคยแต่ได้ยิน ไม่รู้ว่าจะนำไปใช้อะไรอย่างไร อันนี้ผมก็เคยเป็นเหมือนกัน ครับ ว่าเอ มันคืออะไรกัน จนได้มีโอกาสไปเรียน หลักสูตรซอฟต์แวร์ เอนจิเนียริง จึงได้รู้จัก แต่ก็ยังคงไม่ชัดเจน ไม่รู้การนำไปประยุกค์ใช้อย่างไร
ครับ วันนี้เพื่อให้เป้นประโยชน์กับ ท่านที่สนใจ โปรแกรมเมอร์ทั้งหลาย ผมจะกล่าวถึง Design pattern ในเชิงการนำไปใช้ และปฏิบัติ ว่ามันเป็นอย่างไร นำไปใช้อย่างไร ซึ่งในบทความนี้จะกล่าวถึงความหมายของ Design pattern ทำไมเขาถึงพูดว่าเป็นรูปแบบ ของ knowledgs resues และ design pattern มันช่วยให้เราสร้าง software ที่ดีกว่าได้อย่างไร
สำหรับ Design pattern นั้นมีอยู่มากมาย หลากหลายการนำไปใช้ ซึ่งผมก็คงจะไม่พูดทั้งหมด ก็จะขอพูด เฉพาะ singleton factory model-view-controller และ command pattern ครับ และก็จะพูดถึงการ ใช้งานร่วมกัน เพื่อสร้าง software ให้มีสถาปัตยกรรมที่มี ความ ทนทานและ ยืดหยุ่น ตามหลักของ software engineering และจะแสดงให้เห็น ถึงการ แยก businesslogic จาก presentation layer โดยการใช้งาน model-view-controller และรวมถึงการใช้ command polymorphism โดยใช่้ command pattern ครับ…
สิ่งที่สำคัญ ครับคือการที่เราสามารถเขาใจการทำงานและการนำไปใช้ แล้ว จะเปลี่ยนวิถีการสร้าง software architecture ตลอดไป ครับ …
การส่งข้อมูลระหว่าง forms โดยการใช้ delegates technique #2
Dec 31st
“30 ลิขิตฟ้า 70 ต้องฝ่าฟัน” … ครับ คำนี้เป็นจริงแน่แท้ ครับ เราเหล่าโปรแกรมเมอร์ เหมือน นักประพันธ์หนังสือ code ที่เราบรรจงเขียนก็เหมือนกับการเรียงร้อยถ้อยคำในหนังสือก็ไมปาน ความสวยงามของ code คืองานที่ โปรแกรมสร้างสรรค์ มันออกมา ฮา ๆ นี่เป็นสิ่งที่ ผมมีความภาคภูมิใจ และอาจเป็นความไฝ่ฝันของคนรุ่นใหม่อีก มากมาย – แต่การก้าวมาเป็น มืออาชีพต้องอาศัยความพยายามอย่างยิ่ง และอาจต้องสูญเสียบางสิ่ง ไปอีกด้วย – ฮะ ฮะ นี่เป็นอารมณ์ ในบาง อารมณ์ นะครับ
เรื่อง ที่ผมจะพูดในตอนนี้เป้นเรื่อง ต่อจากบทความที่แล้ว ของผม ครับเป็นเรื่องของการส่งผ่านข้อมูลระหว่าง form โดยใช้ delegates เทคนิค นะครับเราได้แสดงกรณีศึกษาแรกไปแล้วเป็น การส่งข้อมูลจาก Main form หรือ Parent form ไปยัง child form ซึ่งเป็น form ที่ ถูกสร้างขึ้นมาจาก Main form …
สำหรับ ในตอนนี้จะเป็นการ ส่งข้อมูลจาก child form กลับไปยัง Main form ครับ โดยเราได้กำหนด scenario ดังนี้ กรณีที่สอง windows forms (parent) ที่มี Listbox จะทำการเปิด dialog form ซึ่ง มี Textbox และ ปุ่มสองปุ่ม คือ (Add item) และ (Close) เมื่อใดก็ตามที่ ผู้ใช้ Click Add button item จะถูกเพิ่มเข้าไปที่ Listbox ใน parent form โดยไม่ต้องปิด dialog นี้ สำหรับปุ่ม close ใช้สำหรับการปิด Dialog …
สำหรับ scenario นี้เราจะทำการ สร้าง delegate ที่รับ Parameter เป็นข้อมูลชนิด string อีกเช่นเคย ซึ่งจะให้ชื่อว่า AdditemDelegate. ใน dialog ลูก เราจะทำการ declare method ที่เป็นชนิด AddItemDelegate ส่วนที่ Mainform เราจะทำการ สร้าง callback function ไว้ เพื่อรับการทำงานของ delegate ครับ

ซึ่งเราจะสร้าง form ขึ้นดังรูป นะครับ จะคล้าย ๆ บทความแรกที่เราเขียน มี Main form frmchild1 และ frmchild2 ครับแต่คราวนี้เราจะทำการ ส่งข้อมูลจาก child form เข้าไปยัง listbox ใน Main from ดังรูป ครับ ต่อไปเรามาดู code กันนะครับ อันดับแรกเราจะทำการ ประกาศ delegate ไว้ ที่ใดก็ได้ ภายนอก class และ ต้องเป็น namespace เดียวกัน ครับ ใขตัวอย่างนี้เราจะประกาศไว้ใน program.cs ดังนี้
...
using System.Windows.Forms;
namespace WindowsApplication3
{
public delegate void AddItemDelegate(string item);
static class Program
{
///
/// The main entry point for the application.
///
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new frmMain());
}
}
}
ส่วนต่อมา เป็นการประกาศ callbackmethod ของ AddItemDelegate ครับ เพื่อมีไว้สำหรับสร้าง trigger และส่ง ข้อมูลกลับไปนะครับ
...
using System.Windows.Forms;
namespace WindowsApplication3
{
public partial class frmChild1 : Form
{
public frmChild1()
{
InitializeComponent();
}
private void frmChild1_Load(object sender, EventArgs e)
{
}
public AddItemDelegate AddItemCallback;
private void btnAdd_Click(object sender, EventArgs e)
{
AddItemCallback(txtMessage.Text);
}
}
}
และใน child 2 from ก็เช่นเดียวกันนะครับ เราประการ callback function ไว้ชื่อว่า “AddItemCallback”
...
using System.Windows.Forms;
namespace WindowsApplication3
{
public partial class frmchild2 : Form
{
public frmchild2()
{
InitializeComponent();
}
private void frmchild2_Load(object sender, EventArgs e)
{
}
public AddItemDelegate AddItemCallback;
private void btnAdd_Click(object sender, EventArgs e)
{
AddItemCallback(txtMessage.Text);
}
}
}
จะเห็นว่าทั้งสอง form จะประกาศ callback fuction ไว้เพื่อเป็นการ trig ทำให้เกิด event ขึ้น ไปกระตุ้นให้ supscriber ใน Main form ทำงาน ซึ่งการทำงาน นี้ขะเกิดขึ้นโดยอัตโนมัติ นะครับ
สุดท้ายเรามาดู ที่ Main form นะครับ
...
using System.Windows.Forms;
namespace WindowsApplication3
{
public partial class frmMain : Form
{
public frmMain()
{
InitializeComponent();
}
private void btnChild1_Click(object sender, EventArgs e)
{
frmChild1 mychild1 = new frmChild1();
mychild1.AddItemCallback = new AddItemDelegate(this.AddItemCallbackFn);
mychild1.Show();
}
private void btnChild2_Click(object sender, EventArgs e)
{
frmchild2 mychild2 = new frmchild2();
mychild2.AddItemCallback = new AddItemDelegate(this.AddItemCallbackFn);
mychild2.Show();
}
private void AddItemCallbackFn(string item)
{
listBox1.Items.Add(item);
}
}
}
ครับ จะเห็นว่าใน Main form นั้น ได้มีการ add supscriber ให้กับ callback function ของแต่ละ form นะครับ ที่ บรรทัด 17 และ 24 ซึ่ง function นี้จะถูกเรียกทำงาน เมื่อ callback function ที่อยู่ใน child 1 หรือ child 2 form ถูกเรียกและส่ง ผ่าน parameter มาให้ ครับ นั่นก็เป็น ตัวแย่างที่แสดงให้เห็น วิธีการหนึ่งในการ ส่งผ่าน ข้อมูลระหว่าง form ในรูปแบบต่าง ๆ นะครับ หวังว่าจะเป็นประดยชน์ต่อ ท่านที่สนใจทั้งหลาย นะครับ
s_teerapong2000@yahoo.com , Senoir programmer – soft speed solution co,.Ltd
การส่งข้อมูลระหว่าง forms โดยการใช้ delegates technique
Dec 29th
Deletegates เป็นคุณสมบัติที่น่าสนใจเป็นอย่างยิ่ง ของ .Net Framework ซึ่งเราทราบกันว่า หน้าที่การใช้งานหลักของมัน คือการสนับสนุนการทำงานของ event handling และ กลไกของการทำ callback. ในบทความนี้เราจะศึกษาวิธีการ ใช้งาน callback ของ deletegate เพื่อใช้สำหรับการสื่อสารระหว่าง windows forms
กรณีตัวอย่าง
การเขียนโปรแกรม ในหลาย ๆ กรณี เราใช้ windows form เปิด windows form อื่น ๆ windows form ที่ถูกสร้าง และ windows form ที่เป็นผู้สร้าง อาจจะต้องมี การส่งข้อมูลระหว่างกัน เช่น เราเลือกรายการใน combobox ใน windows form ที่ถูกสร้าง เราอาจต้องการ ส่งข้อมูลที่เลือกนี้ไปยัง form แม่ หรือ เรามีการเปลี่ยนแปลงข้อมูลใน form แม่ และต้องการส่ง การเปลี่ยนแปลงนี้ไปยัง form ลูกเป็นต้น เหตุการณ์ ตัวอย่างที่กล่าว นั้น เรามารถทำได้ ด้วย deletegate ในรูปแบบ callbacks.
กรณีศึกษา เราจะทำการศึกษา ผ่าน 2 กรณี ดังนี้
- กรณีแรก Windows form (parent) ที่สามารถเปิด windows form อื่น ๆ (children) โดยที่ parent form มี Textbox เมื่อใดก็ตามที่ข้อมูลใน Textbox เปลี่ยน จะส่งการเปลี่ยนแปลงไปยัง children forms และแสดงผล
- กรณีที่สอง windows forms (parent) ที่มี Listbox จะทำการเปิด dialog form ซึ่ง มี Textbox และ ปุ่มสองปุ่ม คือ (Add item) และ (Close) เมื่อใดก็ตามที่ ผู้ใช้ Click Add button item จะถูกเพิ่มเข้าไปที่ Listbox ใน parent form โดยไม่ต้องปิด dialog นี้ สำหรับปุ่ม close ใช้สำหรับการปิด Dialog …
บางท่านบอกว่า ไม่เห็นยากเลย เราก็ทำให้ control เป็น public ซะสิ อืม ก็ได้แต่ว่า มันไม่ใช่ นะครับ เราควรจะรักษา control ให้เป็น private และใช้ delegates แทน ครับ
เรามาดูกันที่ กรณีแรกกันก่อนนะครับ เราจะทำการสร้าง Form ดังต่อไปนี้นะครับ ผม อนุมานเอาว่า ผู้ที่ติดตามอ่าน รู้เรื่อง form และ controls ดีนะครับ

จะเห็นว่าเราสร้าง Form ขึ้นมาทั้งหมด 3 forms ด้วยกันนะครับ ซึ่งก็ประกอบด้วย Main form frmChild1 และ frmChild2 ใน Main form นั้นจะเห็นว่ามี button ที่ใช้ click เพื่อสร้าง form ลูก 2 ปุ่ม คือ Open child 1 และ Open Child 2
นอกจากนั้น Main from ยังมี Textbox เพื่อให้สามารถใส่ข้อมูลอะไรบ้างอย่างลงไปได้ (ใช้สำหรับการส่งข้อมูลไปยัง form ลูกครับ )
ส่วนที่ form ลูก ทั้งสอง forms นั้นมีลักษณะเหมือนกันคือ มี TextBox เพื่อไว้แสดงข้อมูล นะครับ
ความคาดหมายของ โปรแกรมทดสอบนี้ ก็คือเมื่อเรา Run โปรแกรมขึ้นมาเราจะได้ Main form เมื่อ Click ไปที่ ปุ่ม “Open Child 1″ หรือ “Open Child 2″ form ลูก จะถูกสร้างขึ้น ตามที่ปุ้มคลิก เมื่อเรา ใส่ข้อมูลลงใน Textbox ของ Main form ข้อความที่ใส่ลงไปนั้นจะ ถูกส่งไปแสดงที่ form ลูกทั้งสอง พร้อม ๆ กันเลย ครับ
ดังนั้นเราก็มาดู ที่ code กันนะครับ
Listing-01 : Main function …
...
using System.Text;
using System.Windows.Forms;
namespace WindowsApplication2
{
public delegate void SetParameterValueDelegate(string value);
public partial class frmMain : Form
{
public frmMain()
{
InitializeComponent();
}
public SetParameterValueDelegate SetParameterValueCallBack;
private void btnOpenchild1_Click(object sender, EventArgs e)
{
frmChild1 frm1 = new frmChild1();
this.SetParameterValueCallBack += new SetParameterValueDelegate(frm1.SetParamValueCallBackFn);
frm1.Show();
}
private void txtMessageBox_TextChanged(object sender, EventArgs e)
{
SetParameterValueCallBack(txtMessageBox.Text);
}
private void btnOpenchild2_Click(object sender, EventArgs e)
{
frmChild2 frm2 = new frmChild2();
this.SetParameterValueCallBack += new SetParameterValueDelegate(frm2.SetParamValueCallBackFn);
frm2.Show();
}
}
}
ใน Mian form นี่ เรา declare delegate ไว้ นะครับ ในบรรทัดที่ 7 และต่อมาในบรรทัดที่ 15 เราก็ทำการ ประกาศ function ที่เราจะใช้ trig หรือ ส่งสัญญาณไปยัง subscrib ที่อยู่ใน form Child 1 และ Child 2 ครับ
หลังจากนั้น ใน event Click ของ ปุ่มทั้งสองเรา จะทำการสร้าง form Child 1 , Child 2 เราจะเห็นว่า จะมี การ subscrib ไว้ในแต่ละ form ว่าหากมีการ trig จาก Main form ขึ้นมาจะเรียก function อะไร ในแต่ละ form ครับ ในบรรทัดที่ 20 และ 32 นะครับจะเห็น ว่าแต่ละ form นั้นกำหนดไว้ว่า หากมีการ trig เกิดขึ้นที่ Main form จะเรียก function ชื่อว่า “SetParamValueCallBackFn เหมือนกันเลย นะครับ อันที่จริงเราไม่ต้องให้เหมือนกันก็ได้นะครับ
และสุดท้านที่สำคัญก็คือ trigger ที่จะทำให้ เกิดการทำงานขึ้นนั้นเราใส่ไว้ใน event ของ TextBox ชื่อว่า TextChange นะครับ เมื่อใดก็ตามที่ ผู้ใช้พิมพ์ ข้อความลงไปในช่องนี้ ก็จะไปปรากฎที่ form ลูกทั้งสองด้วย บรรทัดที่ 26
ต่อไปมาดู code ของ form ลูกทั้งสองเลยนะครับ
[frmChild1]
......
using System.Text;
using System.Windows.Forms;
namespace WindowsApplication2
{
public partial class frmChild1 : Form
{
public frmChild1()
{
InitializeComponent();
}
public void SetParamValueCallBackFn(string value)
{
txtMessageBox.Text = value;
}
}
}
[frmChild2]
using System.Text;
using System.Windows.Forms;
namespace WindowsApplication2
{
public partial class frmChild2 : Form
{
public frmChild2()
{
InitializeComponent();
}
public void SetParamValueCallBackFn(string value)
{
txtMessageBox.Text = value;
}
}
}
ครับ สำหรับ code ของ form ลูกทั้งสอง นั้นก็ implement function ที่ชื่อว่า SetParamValueCallBackFn(string value) ไว้เพื่อให้เมื่อมีการ trig เกิดขึ้นที่ Main form ก็จะทำให้ function ที่ได้มีการ subscrib ไว้ทำงาน ซึ่งก็คือ function ที่กล่าวมานั่นเอง ครับ ก็เป็นอันว่า การทำงาน สมบูรณ์ นะครับ ถ้ายังไม่เข้าใจ ขอให้ทำตามตัวอย่าง ให้ครบแล้วลอง Run ดูนะครับ
สำหรับ กรณีศึกษาที่สอง ขอไว้เป็นตอนที่สองก็แล้วกันนะครับ
หากยังไม่เข้าใจเรื่องของ delegate นะครับ ก็ขอให้ไปอ่าน ทำความเข้าใจ ก่อนนะครับ ตาม link นี้
Delegates and Event ตอนที่ 1
Delegates and Event ตอนที่ 2
Delegates and Event ตอนที่ 3
Delegates and Events ตอนที่ 1
Dec 27th
Class ต่าง ๆ เป็น Reference type หมายถึง ตัวแปรของ Obeject ของ Class นั้น ไม่ได้อ้างอิงไปยัง Object โดยตรง แต่ชี้ไปยังที่ตำแหน่งใน Address ของ Object แทน ซึ่งทำให้เราสามารถใช้งาน Object ในรูปแบบพิเศษได้มากมาย Delegates ก็เป็นตัวแปรอีกชนิดหนึ่งที่เป็นลักษณะ Reference type Deletgates นั้น สามารถที่จะชี้ไปยัง Method หรือ Reference ไปยัง Method ได้ในขณะ runtime นั่นก็หมายถึงเราสามารถ ที่จะเลือกได้ว่า เราจะ สั่ง Method ไหนทำงานก็ได้ ในขณะ runtime ขึ้นอยู่กับ ความต้องการในขณะนั้น
ในส่วนนี้ผมจะพูดถึงเรื่อง การสร้าง Deletgates การทำ multicast delegates และ วิธีการใช้ event กับ delegates
Deletgates เป็นตัวแปร แบบ Reference type สามารถที่จะอ้างอิงไปยัง method ใด ๆ ก็ได้ delegate ใน C# คล้ายกับ function pointer ใน C++ เพื่อให้เกิดความเข้าใจ พิจารณาจาก code ต่อไปนี้
// Delegate declaration
public delegate void MyDelegate(string ArgValue);
public void DelegateFunction(string PassValue)
{
// Method implement here
}
public void UseMethod()
{
// Delegate Instantiation
MyDelegate DelegateObject = new MyDelegate(DelegateFunction);
}
จาก code ด้านบน บรรทัดแรกคือการประกาศ delegate สังเกตุรูปแบบของการประกาศเป็นไปตาม syntax นี้
delegate <return type> <delegate-name> <parameter list>
จาก code ตัวอย่าง delegate ชื่อ MyDelegate ไม่ return ค่าและมี parameter 1 ตัวคือ PassValue ซึ่งมีชนิดเป็น string สำหรับ function ที่เราจะทำ delegate ก็จะต้อง มีการกำหนด signature ให้ตรงกับ delegate ที่ประกาศไว้ จากตัวอย่าง คือ function ถัดมา ชื่อว่า DelegateFunction ซึ่งได้มีการประกาศ signature ไว้ตรงกับ delegate ด้านบนทุกประการ หลังจากนั้น การใช้งานเราจำทำการ instantiate Delegate object คล้ายกับการ Instantiat object ของ Class เพียงแต่ว่า นี้เป็น object ที่เป็นdelegate โดยจะส่งชื่อ function ที่ต้องการเป็น Parameter ของ delegate constructure
Mydelegate DelegatObject = new MyDelegate(DelegateFunction);
หลังจากนั้น การใช้งานเราสามารถที่จะเรียก DelegateObject แทนชื่อ function ได้เลยและเป็นลักษณะ reference สามารถที่จะส่งผ่าน DelegateObject เป็น argument ของfunctionใด ๆ ที่ต้องการใช้ function เป็น parameter ได้เลย ซึ่งจะได้เห็นการใช้งานในรูปแบบต่าง ๆต่อไป
การใช้งาน Delegate
เพื่อให้เห็น ภาพมากขึ้นจะขอยกตัวอย่างการเรียกใช้ function ปกติขึ้นมาพิจารณาเพื่อนำไปสู่การใช้งาน ขอให้พิจารณาจากตัวอย่างนี้นะครับ
namespace MyNameSpace.NoDelegate
{
public class MyClass
{
public void Process()
{
Console.WriteLine(“Process() begin”);
Console.WriteLine(“Process() end”);
}
}
public class Test
{
static void Main(string[] args)
{
MyClass myClass = new MyClass();
myClass.Process();
}
}
}
จาก ตัวอย่าง เป็นการใช้งานทั่วไปสำหรับการเรียกใช้ function สมมุติว่าถ้าหากเราไม่ต้องการเรียกใช้ function ตรง ๆ หล่ะหากเราต้องการที่จะส่งผ่าน function นี้ให้กับ function อื่นเรียกใช้อีกที โดยเฉพาะการทำงานในลักษณะ event-driven เรามาดูการ ใช้ delegate จากตัวอย่างเดียวกัน
Very basic delegate
namespace ConsoleApplication1
{
public class MyClass
{
public delegate void WriteHandler(string message);
public void Process(WriteHandler writeh)
{
writeh(“Process() begin”);
writeh(“Process() end”);
}
public void writer(string message)
{
Console.WriteLine(message);
}
}
public class Program
{
static void Main(string[] args)
{
MyClass myclass = new MyClass();
MyClass.WriteHandler writehander = new MyClass.WriteHandler(myclass.writer);
myclass.Process(writehander);
}
}
}
ผลของการ ทำงาน จะได้เช่นเดียวกับโปรแกรมแรกนะครับ แต่โปรแกรมนี้เราใช้คุณลักษณะของ delegate พิจารณา class Myclass จะเห็นว่ามีการ ประกาศ Delegate ชื่อ ว่า WriteHandler มี parameter 1 ตัวคือ message และไม่มีการ return ค่าดังนั้น function ที่เราต้องการทำ delegation คือ writer สังเกตุว่า มี signature เหมือนกัน
หลังจากนั้น เราต้องการส่งผ่านฟังก์ชันนี้เขาไปทำงานใน method ชื่อ Process นะครับ สังเกตุว่า Parameter ของ Process นั้นเป็นชนิดเดียวกับ delegate
แล้วสุดท้ายเรามาดูที่ class program ที่ Main เราจะเห็นว่า จะมีการ instantiate delegate object ชื่อ writehander แล้วส่ง method ชื่อ writer เป็น argument ผลก็คือได้ writerhandler ที่อ้างอิงไปยัง writer เราก็โยน writerhandler เข้าไปให้ Process เป็นการส่งผ่าน parameter แบบ reference นะครับ จะเห็นว่าการทำงานครั้งนี้ เราส่งผ่าน function หรือ method เป็น parameter นะครับ นี่แหละการทำงานของ delegate ครับ จะเห็นว่าการทำงานของ delegate นั้นมีขั้นตอนดังนี้นะครับ
จากตัวอย่างที่แล้ว หลายท่านที่เป็น มือใหม่อาจจะยังมึน ๆ ขอตบท้ายด้วย ตัวอย่าง ง่าย ๆ อีกหนึ่งตัวอย่างนะครับ
using System;
namespace Mynamespace.BasicDelegate
{
// #1 Declaration
public delegate void SimpleDelegate();
class TestDelegate
{
public static void MyFunc()
{
Console.WriteLine(“I was called by delegate …”);
}
public static void Main()
{
// #2 Instantiation
SimpleDelegate simpleDelegate = new SimpleDelegate(MyFunc);
// #3 Invocation
simpleDelegate();
}
}
}
เป็นงั้ยครับ พอจะได้ concept ใหม่ครับ ลอง run code ดูนะครับแล้วจะเข้าใจ สำหรับ delegate ขอพอแค่นี้ก่อนนะครับ
ขอให้ติดตาม ในตอน ต่อ ๆไปนะครับเนื่องจากมีการใช้งานอีก หลายลักษณะ ขอให้มีความสุขกับการเรียนรู้นะครับ
สวัสดีชาวโลก !
Jul 28th
Welcome to Teerapong Sontayaman’s Kode talker blog..
ยินดีต้อนรับเข้าสู่ Teerapong Sontayaman’s Kode talker blog.. ที่นี่ เป้น Blog ที่พูดถึงเรื่อง ต่าง ๆ ในการพัฒนาซอฟต์แวร์ ด้วย .Net เทคโนโลยี ทั้งที่เป็น windows application และ web application โดยใช้ C# เป็นหลัก โดยมีความมุ่งหมายที่จะ share เทคนิค และการประยุกต์ รวมถึงประสบการ ต่าง ๆให้กับ ผู้พัฒนา software ทั้งที่เป็นมืออาชีพ และมือสมัครเล่น ของเมืองไทย หวังเล็กๆ ว่าจะเป็นประโยชน์ ไม่มากก็น้อย นะครับ
อันที่จริง Kode talker นั้นผมได้เคยเขียนไว้ที่ http://gpluspluss.wordpress.com/ ตอนนี้ผมได้ การสนับสนุนจาก ทาง Soft Speed Solution ให้มี site เป็นส่วนตัวแล้วจริงได้ย้ายมาเขียนต่อที่นี่ ส่วนที่เดิมก็อาจจะย้ายมา หรือจะทิ้งไว้อย่างนั้น ก็ได้ ขี้เกียจ ย้ายครับ
ธีระพงษ์ สนธยามาลย์ Senior Programmer , Soft speed Solution Co.,Ltd http://www.sssolution.net