Interface Inheritance #2: The Syntax and Polymorphism

    ในบทนี้เรามาเรียนรู้ Syntax ของ Interface Inheritance กัน อย่างที่บอกให้ฟังในบทก่อนว่า Interface Inheritance ของ C# นั้นลอกมาจาก Java ซึ่งแนวคิดเรื่องนี้ของ Java นั้นได้มาจาก C++ เรื่อง abstract class (เราก็ได้เรียนไปแล้วในเรื่อง Implementation Inheritance)  เรามาดู ตัวอย่าง syntax ของ interface กันก่อน

interface IBackup
{
	void Backup();
	void Restore();
}

    จากตัวอย่างนี้เราสร้าง interface ตัวหนึ่งที่ชื่อว่า IBackup ขึ้นมา ข้างในประกอบด้วย method ในการ Backup และ Restore จะสังเกตว่าเราไม่ได้ใส่ modifier public ข้างหน้ามัน syntax มันเป็นอย่างนั้นเอง จะเห็นได้ว่าเราใช้ I เป็นตัวนำหน้าชื่อ Interface ที่มาคือ COM ของ Microsoft ครับ ขึ้นด้วย I สำหรับทุก Interface เพื่อให้เป็นมาตรฐาน เราเลยเอาบ้างครับ

    สิ่งนี้เป็นสิ่งแรกก่อนเราลง code เราต้องคิดรูปแบบ interface ให้ดีเนื่องจากเหตุผลที่เราศึกษามาแล้วในบทก่อนหน้า สมมุติว่าเราคิดดีแล้วสำหรับ Interface ตัวนี้ คราวนี้ถึงตอนที่เรามาใส่ใน class ทำอย่างนี้ครับ

class SQLServer : IBackup
{ 	
	void IBackup.Backup() {
		Console.WriteLine("SQL Server IBackup.Backup()");
	}
	void IRestore.Restore() {
		Console.WriteLine("SQL Server IRestore.Restore()");
	}
	public void hello()
	{
	}
} 
class FoxPro : IBackup
{
	void IBackup.Backup() {
		Console.WriteLine("FoxPro IBackup.Backup()");
	}
	void IRestore.Restore() {
		Console.WriteLine("FoxPro IBackup.Restore()");
	}
	public void world()
	{
	}
}

    สังเกตนะครับว่า หน้าตาของ Method เปลี่ยนไปโดยเติมชื่อของ Interface นำหน้า Method และที่สำคัญมันจะไม่มี Public/Priavate/Protected ใส่ไม่ได้ครับ เป็น syntax

    คราวนี้เรามาดูวิธีใช้กัน

public static void Main()
{
	FoxPro db1 = new FoxPro();
	db.world();
	db1.Backup();
	db1.IBackup.Backup();
}

    แบบนี้ใช้ไม่ได้ครับ แล้วจะใช้อย่างไร ก่อนอื่นผมต้องอธิบายก่อน เรื่องความรู้พื้นฐานเกี่ยวกับ Interface

ความรู้พื้นฐานเกี่ยวกับ Interface

    เมื่อคุณสร้าง class ตัว class นั้นก็จะมี 1 interface ซึ่ง interface นั้นชื่อเดียวกับ class เราเรียกว่าเป็น default interface แต่ class นี้ไม่ได้มีได้เพียงแค่ interface เดียว มีได้หลายเลย แต่ว่าคุณต้องระบุว่าอยากดู ผ่าน interface ไหน ทำได้โดยการ cast ครับ เรามาดูตัวอย่างเพื่อความเข้าใจครับ

FoxPro db1 = new FoxPro();

    อันนี้เป็นการสร้างตัวชี้แบบ default interface ของ FoxPro ครับ ดังนั้นถ้าเรามองผ่าน db1 เรามองได้แค่ Interface ที่เป็น default Interface เท่านั้น ในตัวอย่างนี้ เรามองผ่าน db1 เราจะเห็นเพียงแค่ Method world() ครับ

    ส่วนที่เรา new() นั้นเป็นการสร้าง object จาก class Foxpro ซึ่ง class Foxpro นั้นมี 2 interfaces ซึ่งก็คือ default interface และ Ibackup คราวนี้เรามาลองซิว่า เราจะมองให้เห็น backup() และ restore() ได้อย่างไร

IBackup ib = (IBackup)db1;

    บรรทัดนี้แหละครับคือหัวใจ บรรทัดนี้เป็นการสร้างตัวชี้ใหม่ ซึ่งสามารถมองเห็น interface แบบ IBackup ได้อย่างเดียว ต่อมาคุณก็ assign ให้เท่ากับ db1 ความหมายก็คือให้มันชี้ไปที่เดียวกับ db1 ชึ้ ซึ่งก็เป็น object แบบ FoxPro นั่นเอง อย่าลืมนะครับว่า object แบบ Foxpro มี 2 interfaces 

    จำเป็นกฏเลยนะครับ ตัวชี้นั้นชี้ได้เพียงแค่ interface เดียว แต่ตัว object นั้นเก็บได้หลาย interface

    เรามาดูกันว่า ib เห็นอะไรบ้าง

ib.Backup();
ib.Restore();
ib.world();

    ib.world() ไม่เห็นนะครับเพราะมันเป็นของ Default Interface

    เรื่องการ cast เราไม่จำเป็นต้องระบุ ถ้าเราจะ cast มาเป็น interface แต่ถ้า cast มาเป็น default interface ต้องระบุครับ ตัวอย่างครับ

ib = db1;
db1 = (FoxPro)ib;

    สงสัยอะไรไหมครับ ว่ามันคล้ายเรื่อง Polymorphism ใช่ครับ Interface Inheritance ทำ Polymorphism ได้โดยวิธีนี้ครับ

    มีกติกาข้อหนึ่งที่คุณต้องรู้ไว้นะครับ มันเป็นกฏเลยคือว่า คุณต้อง Implement ทุก Method ใน Interface จะเลือกที่จะ implement แค่เพียงบางตัวไม่ได้ ยกเว้นกรณีข้างล่างนี้ครับ

    มี Syntax เพิ่มเติมที่ผมไม่ค่อยชอบเท่าไหร่ คือสมมุติว่าถ้าคุณไม่ได้ implement interface เช่น IBackup.Backup() มันจะไปมองหา public Backup() ของ default Interface แล้วถ้าเจอมันจะเรียกตัวนี้ใช้เลย ผมไม่ชอบแนวคิดนี้อย่างมาก มันควรจะแยกส่วนให้ชัดเจนไปว่า นี่เป็นของ interface ไหน คงต้องการความสะดวกมั๊งครับ แต่ผมไม่เห็นด้วยกับวิธีนี้ ผมเลยไม่เขียน code ให้ดูนะครับ คิดว่าคุณคงมองออกอยู่แล้ว