Encapsulation

    จากประวัติการสร้างภาษาในการเขียนโปรแกรม ผมเริ่มจากภาษา Machine Language แล้วต่อด้วย Assembly Language จากนั้นก็มาถึงสิ่งที่เราคุ้นเคยคือพวกภาษา Fortran, C ซึ่งเป็นภาษายุคที่สาม แล้วผมก็ข้ามไปคุยเรื่อง class เพราะจะได้เห็นภาพ มาบทนี้ผมย้อนกลับมาเรื่องต่อจากภาษายุคที่สาม

    ตามความเข้าใจของผมมันเป็นเรื่องผิดพลาดของการนิยามคำ ผมว่านะภาษายุคที่สี่น่าจะเป็นภาษาทางด้าน OOP แต่ก็มีผู้นิยาม มันเป็นภาษาด้านการเขียน Database ไปเสียนี่ กลายเป็นว่าภาษาทำนอง Informix, Progress กลายเป็นภาษาระดับสูงมากๆ ไป เขามองที่ความง่ายของภาษาเป็นหลัก คำสั่งเดียวทำงานตั้งแต่ต้นจนจบ ผมไม่ค่อยเห็นด้วยกับการแบ่งลักษณะนี้เลย คราวนี้ภาษายุคที่ 5 กลายเป็น PROLOG โลกนี้เข้าใจยากจัง

    ถ้าผมถือเอาตามนี้ OOP มันก็น่าจะถือว่าเป็นภาษายุคที่ 3.5 ซึ่งอาจจะไม่ผิดนักเพราะมันเก่าแก่พอสมควร อายุภาษา OOP นั้นมันก็กว่า 30 ปีแล้ว เรามาดูประวัติกันหน่อยดีกว่าไหมครับ

    หลังจากภาษายุคที่สามเช่น Fortran เริ่มบูม ก็อย่างที่อธิบายให้ฟังว่ามันมีแนวคิดใหม่สองแนวคิดคือ Abstract Data Type และ การมองสิ่งต่างเป็นวัตถุ จนมาปี 1965 มีภาษาแนวคิดใหม่เกิดขึ้นที่นอร์เว ชื่อว่าภาษา Simula I และพัฒนามาเป็น Simula 67 ภาษานี้ถือว่าเป็น OOP ภาษาแรกของโลก แนวคิดของ Class เริ่มขึ้นที่นี่ รวมทั้งแนวคิดเรื่อง Inheritance ด้วย จากนั้นภาษา SmallTalk, C++ และ ADA ก็นำเอาแนวคิด OOP ของ Simula ไปใช้ 

    เรามาดูกันว่า Simula ให้แนวคิดอะไรใหม่กับเรา เขามองว่า แนวคิดของ ADT และ Object น่าจะเอามารวมกันได้ ในส่วนของ ADT น่าจะเพิ่ม syntax ในส่วนของการสร้างชนิดของตัวแปร ซึ่งก็ได้ผลลัพธ์มาเป็น class ที่เราเพิ่งเรียนกันมา  และ้นแบบนี้สามารถไปสร้างเป็น objects ต่อๆ ไป เป็นการรวมเอาสองแนวคิดเป็นหนึ่งเดียวได้ธรรมชาติมากครับ

    ผมไม่แน่ใจว่าใครเป็นผู้บัญญัติศัพท์คำว่า Object Oriented Programming จะมีมาตั้งแต่ยุค Simula เลยหรือไม่ผมก็ไม่แน่ใจ หรือหลังจากนั้นผมก็ไม่ทราบได้ นั่นไม่สำคัญ สิ่งที่เราสนใจคือแนวคิดของ OOP วันนี้เรามาเรียนกันเรื่อง Encapsulation

    แนวคิดของ Encapsulation เป็นแนวคิดที่พัฒนาต่อมาจาก Abstraction เรามาวิเคราะห์คำนี้หน่อยครับ Abstraction คือการที่ให้เรามองในมุมใหม่ซึ่งมองเป็นสิ่งเดียว เช่น เราเอา IC และสิ่งต่างๆ มารวมกัน ดูวุ่นวายไปหมด แต่เราเรียก Abstract ของมันว่าเป็น โทรทัศน์ แนวคิดของ Abstraction มันดูดีนะครับ แต่มันก็ยังไม่สมบูรณ์ จึงมีการนิยามแนวคิดใหม่เรื่อง Encapsulation ขึ้นมา

    Encapsulation เป็นแนวคิดที่ขยายมาจาก Abstraction ในเมื่อเราใช้ Abstraction เพื่อบังเราจากความยุ่งยากแล้ว เราก็เพิ่มแนวคิดที่ว่า เมื่อเราสรุปว่าเรา Abstract สิ่งยุ่งยากต่างๆ เป็นสิ่งใหม่แล้ว สิ่งใหม่เหล่านั้นต้องมีคุณสมบัติสองอย่างเพิ่มขึ้นคือ

  1. ต้องรวบรวมสิ่งต่างๆ ที่เกี่ยวกับ Abstract นั้นมาให้หมด

  2. ต้องซ่อนสิ่งที่ผู้ใช้ไม่ควรเห็น

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

    ในภาษาทาง OOP ส่วนมากแล้วใช้ class มาเป็นตัวชูโรงในการจัดการเรื่อง OOP แต่ก็ไม่ได้หมายความว่าคุณใช้ class แล้วมันจะหมายความว่าคุณเขียน code เป็นแบบ OOP เลยโดยอัตโนมัติ ซึ่งเดี๋ยวเรามาดูตัวอย่างกัน

    เราสร้าง object ขึ้นมาจาก class object นั้นควรมีคุณสมบัติเป็น black box หรือกล่องดำ ซึ่งหมายความว่าคุณไม่ต้องไม่รู้ว่ามันทำงานภายในได้อย่างไร และคุณไม่จำเป็นต้องรู้ และบางทีก็ไม่ควรรู้ เพราะรู้แล้วยุ่งครับ เมื่อมันเป็นกล่องดำ ใครก็จะเข้าไปยุ่มย่ามกับมันไม่ได้ ดังนั้นจึงมีการส่ง message เข้าไป และมันจะให้ผลลัพธ์ออกมา มันมีอิสระครับในการที่จะตอบสนองกับ message ที่ส่งเข้าไป เช่นถ้าเรามี object หมา เราส่ง message ไปว่าอาหารมาแล้ว ถ้ามันหิวมันจะกิน ถ้ามันไม่หิวมันก็อาจเดิีนหนี อันนี้ขึ้นอยู่กับมันครับ

    เรามาดูกันต่อเรื่อง message ใน OOP เราเรียกมันว่า Interface คือซึ่งก็หมายความถึงส่วนที่ติดต่อกับโลกภายนอกนั่นเอง ในส่วนของ interface นี้แบ่งออกเป็นสองส่วนในโลกของการเขียนโปรแกรม ซึ่งได้แก่

    Property จริงๆ แล้วก็คือตัวแปร ส่วน Method ก็คือ function มันต่างจากตัวแปรหรือ function ธรรมดาก็ตรงที่ถ้าเป็น function หรือตัวแปรธรรมดานั้น มันใช้งานภายในobject เท่านั้น ซึ่งก็มี modifier เป็น private ส่วน Method/Property เป็น function และตัวแปรที่ภายนอกเรียกใช้ได้ มันเลยมี modifier เป็น public

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

Pitfall #1

class book_and_magazine
{
	
}

    นี่เป็น class เกี่ยวกับ หนังสือและวรสาร แบบนี้ผมบอกคุณว่า code นี้ไม่เป็น OOP ครับ! เพราะอะไรคุณอาจสงสัย มันตกข้อ Abstraction ครับ คือเมื่อคุณรวบมาเป็นสิ่งหนึ่ง มันควรมีความหมายเดียว แต่นี่มีสองความหมาย มันทำให้สับสนครับ ใน class นี้มันต้องมี Methods/Properties ของ หนังสืออยู่จำนวนหนึ่ง ของวรสารก็จำนวนหนึ่ง และรวมกันทั้งหนังสือและวรสารอีกจำนวนหนึ่ง ถ้าคุณเป็นผู้ใช้ class ที่ไม่ค่อยรู้เรื่องเลย อยู่ดีๆ ก็มีใครก็ไม่รู้เอา class นี้มาให้ลองใช้ คุณจะงงมากเลยว่า method หรือ property ไหน สำหรับ book และ ตัวไหนบ้างที่ใช้กับ magazine ได้ ใช้ผิดใช้ถูกแน่นอนครับ ในเชิง OOP แล้วเราบอกว่า class นี้ต้องแตกเป็นสองตัวครับคือ class Book และ class Magazine

    คุณคงเห็นแล้วนะครับว่า ว่าถึงแม้ว่าคุณใช้ class ก็ไม่ได้หมายความว่าคุณเขียนแบบ OOP โดยอัตโนมัติ

Pitfall #2

class Book
{
	public string title;	
}

    ผมแยกเป็น class Book แล้ว ใน class นี้ผมเก็บชื่อหนังสือ ถ้าผมบอกคุณว่าเขียนแค่นี้ก็สอบตก OOP แล้ว! คุณอาจจะงงซ้ำสอง จริงๆ ครับมันสอบตกจริงๆ เมื่อคุณสร้าง property แบบนี้ให้เป็น public คุณตกเรื่อง Encapsulation ทันที เพราะ title ถือเป็นข้อมูลสำคัญ ของ class นี้เลยทีเดียว ถ้าคุณเปิดโล่งแบบนี้ ใครก็ได้เข้ามาแก้ไขได้ แล้วคุณจะรู้ไหมว่าใครที่ไหนเป็นผู้แก้แล้วทำให้ค่ามันเพี้ยน ตัวอย่างนี้อาจจะไม่ชัดนัก แต่ถ้าผมเปลี่ยนจาก title เป็น percent ซึ่งเป็นค่า integer หละ ถ้าคุณปล่อยโล่งไม่มีการควบคุม ใครที่ไหนไม่รู้ แก้โปรแกรมค่า percent ให้เป็น 200 ซึ่งมันเป็นค่าที่เป็นไปไม่ได้ เพราะเปอร์เซ็นนั้นเก็บค่าได้แค่ 0 ถึง 100 เท่านั้น เมื่อ object นั้นเอาค่า 200 ไปใช้มันจะรวนไปหมด แล้วหาไม่ได้นะครับว่าต้นตอที่ทำให้ผิดมันอยู่ตรงไหน หา bug กันหัวโตครับ

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

class Book
{
	private string  title;
	public void set_title(string str)
	{
		title = str;
	}
	public string get_title()
	{
		return title;
	}	
}

        จะเห็นได้ว่าด้วย code นี้เราทำการซ่อน title เอาไว้ไม่ให้ภายนอกเข้ามาแก้ได้ แต่เราก็เตรียม function set_title() และ get_ttile() เอาไว้ให้สำหรับแก้ค่าและดูค่าตามลำดับ ซึ่งใน code ของทั้งสอง function เราสามารถเขียน code เพื่อป้องกันค่าเพี้ยนๆ จากภายนอกได้ อันนี้คือข้อดีครับ แต่ข้อเสียคือดูยุ่งยากครับ ถ้าคุณไปอ่าน code C++ คุณจะเห็นแบบนี้เยอะครับ 

    ในภาษา OOP ยุคใหม่เพิ่ม syntax ทำให้เราสามารถใช้ property ได้อย่างปลอดภัย ใน C# มีการเพิ่ม syntax ดังนี้ครับ

property.cs

using System;

class Book
{
	private string save_title;
	public string  title {
		get {
			return save_title;
		}
		set {
			save_title = value;
		}
	}
}

class Hello
{
	public static void Main()
	{
		Book x = new Book();
		x.title = "C# Programming";
		Console.WriteLine(x.title);
	}
}

Dos Prompt

C:\CS>property
C# Programming

C:\CS>_

   จาก code นี้คุณจะเห็นว่า เราสามารถใช้ property ได้อย่างปลอดภัย โดยการสร้าง อะไรก็ไม่รู้ property ก็ไม่ใช่ method ก็ไม่เชิงเป็น syntax เฉพาะครับที่ชื่อว่า title และ title นี้เองเราใช้เป็น property ในการติดต่อกับโลกภายนอก ภายนอกสามารถ ใช้งานรู้สึกเหมือน property ธรรมดา สามารถใช้เครื่องหมาย = ได้ ภายในอะไรแปลกๆ นี้มี get {} และ set {} เอาไว้ setค่าตัวแปรและดูค่าตัวแปรที่ซ่อนตามลำดับ ลองดู syntax นะครับ ใน get {} ใช้การ return ครับ ส่วน set() นั้นก็ใช้ตัวแปรที่แอบสร้างเฉพาะเพื่อการนี้โดย C# ครับชื่อว่า value เป็นตัวแปรที่ภายนอกพยายามกำหนดค่าเข้ามา คุณสามารถควบคุมได้ครับจะให้หรือไม่ให้เข้า ถ้าไม่ให้คุณจะเลือกที่แสดง error เลยก็ตามใจครับ

    ถ้าคุณบอกว่าตัวแปรตัวนี้ readonly ห้ามเขียน ก็แค่ตัด set {} ทิ้ง เท่านี้ก็อ่านได้อย่างเดียวแต่เขียนไม่ได้ หรือในทางกลับกันนะครับ ถ้าอยากให้เขียนได้อย่างเดียว ก็ตัด get {} ในทำนองเดียวกันครับ

Pitfall #3

    อันนี้ไม่มี code ให้ดู มีแต่คำอธิบาย สมมุติว่าบ้านคุณมีหนังสือเยอะมาก คุณเพิ่งซื้อชั้นวางหนังสือใหม่ สมมุติว่าคุณบอกว่าชั้นหนังสือชั้นบนเอาไว้เก็บหนังสือคอมพิวเตอร์ ถ้ามีหนังสือบางเล่มที่ไม่ใช่หนังสือคอมพิวเตอร์แต่คุณเก็บในชั้นนั้น หรือว่าคุณเก็บไม่ครบ หนังสือคอมพิวเตอร์บางส่วนไปอยู่ในชั้นอื่น แบบนี้เรียกว่าไม่ Encapsulation ครับ ถ้าพูดว่าชั้นหนังสือคอมพิวเตอร์ มันก็ควรจะมีเฉพาะหนังสือคอมพิวเตอร์และควรจะมีครบครับ Encapsulation ในเรื่องของ class มันก็เป็นเช่นนั้น เมื่อคุณสร้าง class book อะไรที่เกี่ยวกับ book มี methods และ properties อะไรบ้างใส่มาให้ครบ และอะไรที่ไม่เกี่ยวกับ book อย่าเอามาใส่ เท่านี้คุณก็ผ่านแนวคิดของ Encapsulation แล้วหละครับ

 

    นี่คือแนวคิดพื้นฐานของ OOP แต่มันไม่ได้มีเพียงเท่านี้นะครับ มันมีรายละเอียดอีกมาก แต่มันไม่ใช่กฏ มันเป็นข้อแนะนำว่าถ้าเขียน OOP ให้ดีต้องทำอย่างไรบ้าง ยังมีการพัฒนาอย่างต่อเนื่องไม่จบนะครับ  มีกลุ่มคนใหญ๋ๆ หลายกลุ่มเลยครับที่มาประชุมกันปรับปรุงแนวคิด แล้วออกมาเป็นคำแนะนำ, หลักวิธี, ปรัชญา ภาษาฝรั่งเรียกมันว่า idiom, pattern, methodology และอื่นๆ อีกมาก กลุ่มหนึ่งที่ผมติดตามอยู่คือ PLoP ซึ่งกลุ่มนี้เป็นกลุ่มที่เป็น pioneer ของภาษา C++ เก่า เขาจะประชุมกันทุกปีเรื่องการพัฒนาแนวคิดของ OOP ซึ่งปี 2001 นี้จะประชุมกันเดือนกันยายน ซึ่งถือว่าเป็นครั้งที่ 8 ครับ ผมก็ได้รับอิทธพลทางความคิดจากกลุ่มนี้เยอะ

สิ่งที่ได้รับจาก Encapsulation

    เรามาคุยกันหน่อยว่า เมื่อเราทำตาม guildline ของ Encapsulation ข้างบนแล้ว code ของเรามีอะไรดีขึ้น