Tags:

เพิ่งเริ่มหัดเขียนโปรแกรม OOP อ่านหนังสือแล้วเจอตอนใช้ Dictionary ตอนประกาศตัวแปรกลับใช้ IDictionary แทน

IDictionary<string, MyClass> dictionary = new Dictionary<string, MyClass>();

ทำไมถึงไม่ใช้

Dictionary<string, MyClass> dictionary = new Dictionary<string, MyClass>();

ทั้งที่การประกาศทั้งสองแบบก็สามารถใช้งาน Dictionary Class ได้เหมือนกัน พยายามลองหาเหตุผลจาก google แล้ว คำตอบที่ได้ไม่ค่อยชัดเจนเท่าไหร่

คำตอบที่พบเช่น
- หากมีการแก้ไข code ในอนาคต ในกรณีที่ต้องการใช้ Class ในกลุ่มเดียวกัน สามารถทำได้ง่ายกว่า
- บางคนบอกให้เลือกตามความเป็น generic มากกว่ากัน
- สามารถ casting ไป Interface หรือ Class ในกลุ่มเดียวกันได้ง่ายกว่า

สรุปว่ามันจำเป็นไหมครับ? ถ้ามันจำเป็นหรือมีข้อดีอื่น ๆ รบกวนช่วยอธิบายหรือตัวอย่าง code ที่จำเป็นต่อการใช้งานแบบนี้ ถ้ามันดีกว่าจริง แล้วเราจะรู้ได้อย่างไรว่า Class ไหนควรประกาศตัวแปรด้วย Interface แทนการใช้ Class ประกาศตรง ๆ ครับ

ผมลองเขียนโปรแกรม casting ดูมันก็สามารถทำได้อยู่แล้วเลยยิ่งสงสัยว่าจะทำไปทำไม

class Program
{
    static void Main(string[] args)
    {
        Dictionary<string, int> myVar = new Dictionary();

        myVar.Add("a", 1000);
        myVar.Add("b", 2000);

        foreach(KeyValuePair<string, int> x in myVar)
        {
            Console.WriteLine("\"{0}\" => {1}", x.Key, x.Value);
        }

        Console.WriteLine("Casting to IDictionary.");

        IDictionary<string, int> testVar = (IDictionary<string, int>)myVar;

        foreach (KeyValuePair<string, int> x in testVar)
        {
            Console.WriteLine("\"{0}\" => {1}", x.Key, x.Value);
        }
    }
}

output:

 
"a" => 1000
"b" => 2000
Casting to IDictionary.
"a" => 1000
"b" => 2000
Get latest news from Blognone
By: kanchen
AndroidUbuntu
on 8 October 2018 - 10:04 #1074944

ผมจะอธิบายความหมายของ interface แล้วกันครับ
- ใน interface จะมีแค่ method และ properties จะไม่สามารถเขียน code ไว้ใน Method ได้ครับ(ถ้าเขียน c# ตอนนี้ใน c# 7.0 จะทำได้มากกว่านี้ครับ)

ในกรณีของ IDictionary<string, MyClass> dictionary = new Dictionary<string, MyClass>();
ถ้าไปดูใน Class Dictionary จะมีการ inherited IDictionary ซึ่ง IDictionary เป็น interface ที่มีแต่ method กับ properites เท่านั้นครับ(จะตรงกับสิ่งที่ผมบอกอยู่ด้านบนครับ) และใน IDictionary เองนั้นยังมีการ
inherited ICollection, IEnumerable อีกด้วยครับ

ผมจะยกตัวอย่างให้เป็นภาพชัดครับ
interface IGetable
{
string Get();
}

interface IAll
{
string All();
}

class Example1 : IGetable, IAll
{
public string Get() { return "Get"; }
public string All() { return "All"; }
}

class Exp1
{
IGetable get1 = new Example1(); //Method ที่สามารถเรียกใช้ได้จะมีแค่ Get()
IAll get1 = new Example1(); //Method ที่สามารถเรียกใช้ได้จะมีแค่ All()
Example1 exp1 = new Example1(); //Method ที่สามารถเรียกใช้ได้จะมีแค่ Get() และ All
}

จากตัวอย่าง Exp1 จะเห็นว่า Example1 จะเป็น class ลูกและมี class แม่เป็น IGetable, IAll ครับ ถ้ามีการ new object จาก class ลูกใส่ใน class แม่ก็จะมีแค่ความสามารถของแม่ครับ

ส่วนถามว่าจำเป็นไม ตอบเลยครับว่าจำเป็นครับ สำหรับ OOP และการเขียนโปรแกรมที่ถูกตามมาตรฐานสากลครับ
ข้อดี OOP มีเยอะมากๆ ครับ

ส่วนที่ถามว่า จะรู้ได้ยังไงว่า Class ไหนจะต้องใช้ Interface หรือใช้ Class แทนได้
ตอบ ถ้าโปรแกรมของคุณมีการเรียกใช้งานจากโปรแกรมอื่นๆ ตรงนี้แนะนำให้ใช้ Interface แทน base class ครับ
ตัวอย่างคือ ถ้าโปรแกรมของคุณต้องการจะทำการ export ไฟล์ excel คุณจะต้องไปเรียกใช้งาน interface
ของ excel มาใช้ เพื่อใช้ในการสร้าง sheet และเขียนข้อมูลลงใน excel

เพิ่มเติมครับ class ที่เป็นจำพวก collection เช่น IDictionary, IList, ICollection, IQueryable,... พวกนี้สามารถใช่ได้ทั้ง
2 แบบนั้นแหละครับ จะ new ใส่ interface หรือ class ก็ไม่ต่างอะไรมาก อาจจะต่างแค่บาง class ครับ เช่น
List กับ IList โดยใน List จะมี method AddRange เพิ่มเข้ามา ส่วน IList จะไม่มี AddRange ครับ
ตรงนี้มันขึ้นอยู่กับการใช้งานต่อด้วยครับ แต่หลักๆ ผมอยากให้คุณเข้าใจหลักการของ interface ก่อนครับ

By: pure88
Windows
on 8 October 2018 - 12:23 #1074990 Reply to:1074944
pure88's picture

ขอบคุณที่ช่วยอธิบายเรื่อง interface ครับ จริง ๆ เข้าใจเรื่อง interface แต่ไม่เข้าใจว่าทำไมถึงใช้แบบนั้น สงสัยน่าจะเพราะผมเริ่ม OOP จาก C++ ครับ เลยรู้สึกขัดแย้งกับความรู้สึกในการใช้ แต่ตอนนี้พอจะมองออกแล้วครับว่าทำไม

By: darktong
ContributorAndroidUbuntu
on 8 October 2018 - 22:13 #1075105

ผมมาจากฝั่ง java นะครับ ไม่มี class Dictionary เลยจะขอยกตัวอย่างแบบ java แทน ในที่นี้จะเปรียบเทียบระหว่าง

Map<String, Object> map = new HashMap<String, Object>();
HashMap<String, Object> map = new HashMap<String, Object>();

จริงๆแล้วทั้งสองอันนี้เหมือนกันครับ แต่การใช้ interface จะมีข้อได้เปรียบกว่าในกรณีที่มีเราต้องการแก้โค้ดไปใช้ Map ตัวอื่นโดยที่ไม่ break โค้ดเดิมที่มีการใช้งานอยู่ เช่น

private void doSomething(HashMap<String,Object>) {
    // ...
}

doSomething จะต้องส่ง HashMap เข้ามาเป็น parameter เท่านั้น ซึ่งโค้ดก็ทำงานได้ปกติ ทีนี้ในภายหลังเราพบว่าเปลี่ยนไปใช้ TreeMap จะดีกว่า ตรงนี้จะทำให้ doSomething ใช้ไม่ได้ ต้องแก้โค้ดใหม่ ซึ่งในกรณีนี้หากเราใช้ interface แทน

private void doSomething(Map<String,Object>) {
    // ...
}

จะเห็นว่า doSomething ยังคงสามารถทำงานได้ปกติไม่มีปัญหา ซึ่งตรงนี้เราใช้ interface แทนเพื่อให้ code ยืดหยุ่นรองรับความเปลี่ยนแปลงได้ ดังนั้นโดยทั่วไปถ้าเป็นไปได้จะนิยมใช้ interface มากกว่าครับ

By: obnetarena
Windows PhoneWindows
on 22 October 2018 - 23:06 #1077733

ที่ประกาศ​ IDictionary เพื่อจะได้สื่อจุดประสงค์ของ ตัวแปรที่เราจะเรียกใช้งานได้ชัดครับว่า จะใช้งานมันแบบ IDictionary ซึ่งจะมี
Method และ Property ตาม IDictionary ระบุไว้เท่านั้น

แล้วมันก็ช่วยให้เราเขียนโค้ดได้ง่ายด้วย เพราะ Intellisense จะแสดงเฉพาะฟังก์ชันของ IDictionary ซึ่งไม่เยอะ

แต่ถ้าเราประกาศเป็น Dictionary ไปเลย จะมี Method + Property มาอีกเพียบเลยครับ

การประกาศแบบนี้ทำให้เราไม่ทำงานเกิดขอบเขตของตัวแปร และที่สำคัญ โค้ดเราก็ปรับปรุงได้ง่ายกว่า

ถ้าวันนึง Dictionary มันไม่เวิร์ค มี Bug บางอย่างที่ทำให้งานเราส่งมอบไม่ได้ แต่ทางต้นทางเค้ายังไม่ยอมแก้ Class Dictionary ให้เราสักที เราก็สามารถที่จะ Implement IDictionary ขึ้นมาเองแล้วเขียนใหม่ให้ทำงานได้แบบเดิมโดยแก้ไข Bug ไปก่อนก็ยังได้ครับ