/ BasicKnowledge

[365 วันแห่งโปรแกรม #day71] Inner Interface

วันที่เจ็ดสิบเอ็ดของ ‪#‎365วันแห่งโปรแกรม วันนี้เป็นเรื่องต่จากครั้งที่แล้วครับ แค่เปลี่ยนจากคลาสเป็นอินเทอร์เฟสแทน ><


Inner Interface

Inner Interface หรือ Nested Interface ก็ไม่ต่างจาก Inner Class กล่าวคือเป็นอินเทอร์เฟสที่เกิดขึ้นมาเพื่อ Outer Class ของมัน

แล้วทำไมต้องมี Inner Interface ?

ในการเขียนโปรแกรมนั้นเราจะพบเจอ Inner Interface บ่อยกว่า Inner Class มากๆ ส่วนใหญ่จะเป็นในเรื่องของ Callback เพราะว่า Callback ของแต่ละคลาส/อินเทอร์เฟส นั้นมีคุณสมบัติเฉพาะตัว และมักใช้ร่วมกันไม่ได้ อีกเรื่องหนึ่งคือเรื่องของ Event Listener ซึ่งก็เป็นเหตุผลเดียวกัน สรุปคือ Inner Interface จะมีบทบาทในการเป็นโครงให้โปรแกรมเมอร์ Implement โค้ด เพื่อนำไปใช้กับ Outer Class ของมัน

เมื่อไหร่ที่ไม่ควรใช้ Inner Interface ?

เช้นเดียวกัน Inner Class เมื่อสิ่งที่เราทำนั้นดูเป็น general มากๆ กล่าวคือเป็นสิ่งที่ควรจะแชร์ให้คลาส/อินเทอร์เฟสอื่นนำไปใช้ได้ด้วย ก็ไม่ควรทำเป็น Inner Interface

ตัวอย่างของการนำไปใช้

สมมติว่าเรามีคลาสสำหรับคำนวนอะัไรบางอย่างที่ใช้เวลายาวนานมากๆ

public class StockUtils{

   StockUtils stockUtils = new StockUtils();

    public float calculateRsiForSymbol(String symbol){
        //do something
        return rsi;
    }

}

public class Program{
    public static void main(String [] args){
        Program p = new Program();
        p.run();
    }

    public void run(){
        String symbol = "NPARK";
        float rsi = stockUtils.calculateRsiForSymbol(symbol);
        //do something
    }
}

การที่เราเรียกใช้เมธอดในคลาสนี้จะเกิด Blocking I/O คือต้องรอเมธอดนี้ทำงานให้เสร็จก่อนถึงจะทำอย่างอื่นต่อไปได้ ดังนั้นเราควรจะเขียนเมธอดนี้ใหม่ให้เป็น Asynchronous แต่ปัญหามีอยู่ว่าพอเป็น Asynchronous ปุ๊บการ return ค่าแบบเดิมนั้นทำไม่ได้ (สมมติว่าภาษาที่ใช้เขียนไม่มี Feature สำหรับจัดการ Asynchronous) ทางออกก็คือสร้าง Callback ให้เมธอดนี้เรียกเมื่อทำงานเสร็จนั่นเอง

public class StockUtils{

    private StockUtilsCallback callback;
    //setter here

    public void calculateRsiForSymbol(String symbol){
       new Thread(new Runnable() {
           @Override
           public void run() {
               //do something in background thread
               callback.calculateRsiForSymbolCompleted(symbol, rsi);
           }
       }).start();
    }

    public interface StockUtilsCallback{

        public void calculateRsiForSymbolCompleted(String symbol, float rsi);

    }

}

public class Program{

   StockUtils stockUtils = new StockUtils();

   public static void main(String [] args){
        Program p = new Program();
        p.run();
    }

    public void run(){
        String symbol = "NPARK";
        stockUtils.setStockUtilsCallback(stockUtilsCallback);
        stockUtils.calculateRsiForSymbol(symbol);
        //do something
    }

    StockUtils.StockUtilsCallback stockUtilsCallback = new StockUtils.StockUtilsCallback() {
        public void calculateRsiForSymbolCompleted(String symbol, float rsi) {
            //do something
        }
    };
}

จะเห็นว่าคราวนี้ calculateRsiForSymbol ไม่คืนค่าแล้ว แต่หลังจากทำงานเสร็จจะเรียกเมธอด calculateRsiForSymbolCompleted ของ Callback interface แทน

จากตัวอย่างนี้แสดงให้เห็นถึงการนำ Inner Interface ไปใช้ทำ Callback เพื่อใช้คืนค่าจาก Background Thread มาให้โปรแกรมหลัก อย่างไรก็ตาม Inner Interface ยังถูกนำไปใช้เพื่อประโยชน์อื่นๆ อีกมายมาย ไม่ว่าจะเป็นการทำ Custom Strategy หรือ Event Listener เป็นต้น

#‎day71 #365วันแห่งโปรแกรม ‪#‎โครงการ365วันแห่ง‬...