เรื่องของตัว I (Interface segregation) ในหลักการ SOLID สำหรับคนเขียน OOP

Screen Shot 2560-08-23 at 12.13.53 AM.png

มาถึงตอนที่ 4 ของซีรีย์ SOLID กันแล้วนะครับ กับตัว I ซึ่งตัวนี้ย่อมาจาก Interface segregation Principle (ISP)  ที่จะทำให้ Code ที่เขียนด้วยภาษา OOP นั้นดูดีมากขึ้นไปอีกขั้น 😉

ISP นั้นกล่าวถึงหลักการที่ว่า

Class ที่มา Implement เพื่อใช้งาน Interface นั้นๆไม่ควรที่จะต้องมา Implement Method ต่างๆให้ครบโดยที่อาจจะไม่ได้ใช้

ซึ่งถ้าตีความง่ายๆที่สุดเลยก็คือ เราควรอย่าไปกลัวกับการที่จะต้องสร้าง Interface ใหม่ เพราะโดนส่วนใหญ่ Developer อาจจะชอบเพิ่ม Method ใน Interface เดิม ซึ่งมันดูปลอดภัยมากกว่านั่นเอง

เราลองมาดูตัวอย่างกัน …

เริ่มแรกเลย

ผมมี Interface ชื่อ IPhone (ไม่ใช่ Appple iPhone นะครับ :D) ซึ่งมีด้วยกันทั้งหมด 6 Methods

interface IPhone {
        call();
        ring();
        installApp();
        addContact();
        connectWifi();
        connectMobile();
    }

ที่นีผมก็ลองสร้าง Class ชื่อ SmartPhone ที่จะมา Implement ตัว Interface IPhone ดูครับ

class SmartPhone implements IPhone {
 public call(){ /* do something /* }
 public ring(){/* do something /* }
 public installApp(){/* do something /* }
 public addContact(){/* do something /* }
 public connectWifi(){/* do something /* }
 public connectMobile(){/* do something /* }
}

เนื่องจากว่า SmartPhone นั้นมีความสามารถครบก็ดูโอเคดีครับที่เราจะออกแบบ Interface IPhone แบบนี้

แต่ถ้าผมมีอีก Class ชื่อ FeaturePhone ที่ต้อง Implement IPhone แต่ไม่สามารถ install App หรือ ต่อ wifi ได้ล่ะ ด้วยมันก็จะเป็นแบบนี้

class FeaturePhone implements IPhone {
 public call(){}
 public ring(){}
 public installApp(){
     throw new Error('Feature Phone does not support apps..');
 }
 public addContact(){}
 public connectWifi(){
     throw new Error('Feature Phone does not support using Wifi..');
 }
 public connectMobile(){}
 }

และถ้าเรามีอีก Class ชื่อ BasicTablet ที่มันทำอะไรไม่ค่อยได้นอกว่า install App กับต่อ wifi  มันก็จะเป็นแบบนี้

 BasicTablet implements IPhone {
 public call(){
    throw new Error('Basic Tablet does not support call..');
 }
 public ring(){
    throw new Error('Basic Tablet does not support ring..');
 }
 public installApp(){}
 public addContact(){
    throw new Error('Basic Tablet does not support contacts..');
 }
 public connectWifi(){}
 public connectMobile(){
    throw new Error('Basic Tablet does not support using mobile..');
 }
}

ซึ่งจากตัวอย่างทั้ง 2 Class นั้นก็จะเห็นได้ว่า การออกแบบ Interface แบบนี้ดูแล้วมันค่อนข้างกว้างไป

.

.

เริ่มการ Refactor

แน่นอนว่า Interface IPhone ที่สร้างไว้ตั้งแต่ต้นนั้นมันกว้างไป เทคนิคที่จะใช้ครั้งนี้คือ Extract Interface ซึ่งก็คือทำการแบบ Interface IPhone ออกมาเป็น Interface ย่อยๆตามกลุ่มของ Method ที่เรามี

ซึ่งถ้าเราสังเกตุดูจาก Interface IPhone นั้นจะมี Method อยู่ 3 กลุ่มคือ

  1. โทร พื้นฐาน
  2. การใช้งาน App
  3. การเชื่อมต่อ

ดังนั้นหลักจากที่ทำการ Extract Method แล้วจะได้ผลแบบนี้ครับ

interface IPhone {
  call();
  ring();
  addContact();
}

interface ISmartFeatures {
  installApp();
}

interface IMobileConnect {
  connectMobile();
  connectWifi();
}

ที่นี้ Class SmartPhone ของเราก็ต้องแก้ Code ให้มาเป็นแบบนี้แทน

class SmartPhone implements IPhone, ISmartFeatures, IMobileConnect {

  public call(){}
  public ring(){}
  public installApp(){}
  public addContact(){}
  public connectWifi(){}
  public connectMobile(){}

}

ส่วน Class FeaturePhone ก็จะเป็นแบบนี้ ซึ่งก็ยังต้องมีการ handle Method ที่ไม่ Support อยู่แต่ว่าก็จะน้อยลงกว่าตอนแรก

class FeaturePhone implements IPhone, IMobileConnect {

  public call(){}
  public ring(){}
  public addContact(){}
  public connectMobile(){}
  public connectWifi() {
    throw new Error('Feature Phone does not support using Wifi..');
  }

}

ส่วน Class BasicTablet นั้นก็จะคล้ายๆกับ FeaturePhone ก็คือ

class BasicTablet implements ISmartFeatures, IMobileConnect {

  public installApp(){}
  public connectWifi(){}
  public addContact(){}
  public connectMobile(){}
  public connectMobile(){ 
    throw new Error('Basic Tablet does not support using mobile..'); 
  }

}

สรุป

เพื่อนๆก็จะเห็นว่าการทำ Interface Segregation นั้นจะทำให้เราสามารถออกแบบ Interface ได้ดียิ่งขึ้นและไม่เป็นการทำให้ Client ของ Interface นั้นต้องมาเขียน  Code  เพิ่มโดยที่ไม่ได้ Handle อะไรเลย รวมถึงทำให้ Class และ Interface ของเราดูแลได้ง่ายขึ้นและเจาะจงการการทำงานแต่ละเรื่องมากขึ้น

SOLID The Series:

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s