SOLID หลักการพื้นฐานที่โปรแกรมเมอร์ควรรู้ (ตอนที่ 4 – ISP)

สำหรับหลัก ISP ของ SOLID Principles ตอนนี้อาจจะเน้นหนักไปทาง Interface นิดนะครับ ดังนั้นถ้าท่านใดยังไม่ค่อยคุ้นกับ Interface แนะนำให้ลองอ่านลิงค์ตามด้านล่างก่อนเริ่มนะครับ

  1. PHP Interface
  2. Java Interface
  3. Why interface is useful? (Stackexchange)

สารบัญสำหรับตอนอื่นๆ

Interface Segregation Principle (ISP)

กฎข้อนี้กล่าวไว้ว่า

no client should be forced to depend on methods it does not use

หมายความว่า

Class ไม่ควรที่จะถูกบังคับให้มี Method ที่ Class นั้นไม่ได้ใช้

ลองมาดูตัวอย่างกันครับ เริ่มแรกเรามี CarInterface  ซึ่งประกอบไปด้วย 3 Method สำหรับการ สตาร์ท, เคลื่อน, และ เติมน้ำมันให้รถ

และเรามีคลาส ToyotaAltis  ซึ่ง Implement CarInterface

และเราก็มีคลาสคนขับรถ Driver ซึ่งมีหน้าที่ในการควบคุมรถยนต์

หลังจากนั้นเราเพิ่มคลาสรถยนต์พลังงานไฟฟ้ารุ่นใหม่ล่าสุด ชื่อ ToyotaIQ ซึ่งไม่จำเป็นต้องเติมน้ำมันเนื่องจากใช้การชาร์จพลังงานไฟฟ้าอย่างเดียว ซึ่งเราก็จะเพิ่ม Method สำหรับการชาร์จไฟฟ้าเข้าไปใน CarInterface

ทำให้เราต้องเพิ่ม Method chargeBattery  เข้าไปใน ToyotaAltis ด้วยแต่เนื่องจาก Toyota Altis เอง ใช้น้ำมันเป็นพลังงาน ทำให้เราต้องสร้าง Method ทิ้งไว้เพื่อให้ไม่เกิด Error เมื่อรันโปรแกรม

เช่นกันสำหรับคลาส ToyotaIQ จะมี Method fillUpFuel  ที่คลาสไม่ได้ใช้

ทีนี้จะเห็นได้ว่าทั้งคลาส ToyotaAltis  และ ToyotaIQ  มี Method ที่ไม่ได้จำเป็นใช้ต้องใช้ แต่ถูกบังคับให้มีเพราะทั้งสองคลาสนั้น Implement CarInterface  และจำเป็นต้องมี Method ทั้งหมดที่ Interface มี และนั่นก็คือการฝ่าฝืนกด ISP นั่นเอง

เริ่ม Refactor

สาเหตุที่ทั้ง 2 คลาสนั้นมี Method ที่ไม่ได้ใช้อยู่ในคลาสนั้นก็เพราะว่า CarInterface  นั้นถูกออกแบบให้ทำงานกว้างเกินไป (Fat Interface) ซึ่งหลัก ISP นั้นก็แนะนำให้เราแบ่งการทำงานของ Interface นั่นให้เฉพาะเจาะจงที่สุด ซึ่งจะทำให้คลาสที่จะ Implement Interface นั้นมีเฉพาะ Method ที่ตัวคลาสนั้นต้องการใช้

มาถึงจุดนี้ประโยคที่ว่า

แบ่งการทำงานของ Interface นั่นให้เฉพาะเจาะจงที่สุด

ทำให้เรานึกถึงหลัก SOLID ข้อไหนบ้างมั้ยครับ? … ใช่แล้วครับหลักการนั้นก็คือ Single Responsibility Principle (SRP) นั่นเอง ถึงตอนนี้เราก็จะทราบแล้วว่าไม่ว่าจะเป็น Class ธรรมดาหรือ Interface ก็แล้วแต่ การออกแบบนั้นก็ต้องทำให้ตัวคลาสหรือ Interface นั้นมีหน้าที่และความรับผิดชอบเพียงอย่างเดียวเช่นกัน

ลองมา Refactor โค้ดก่อนหน้านี้กันครับ โดยผมจะเพิ่ม Interface อีก 2 ตัวด้วยกันนั่นก็คือ FuelFillableInterface  และ BatteryChargeableInterface

และปรับ CarInterface  เป็น

ทีนี้กลับมาที่ ToyotaAltis  ซึ่งเป็นรถยนต์ใช้น้ำมันเชื้อเพลิง ดังนั้นเราสามารถให้คลาสนี้ Implement FuelFillableInterface  ได้ หลังจากนั้นเราก็สามารถลบ chargeBattery  ออกได้

และสำหรับ ToyotaIQ  ก็ให้คลาส Implement BatteryChargeableInterface  และลบ fillUpFuel  ออก

จะเห็นได้ว่าตอนนี้ทั้ง 2 คลาส ToyotaAltis  และ ToyotaIQ มีเพียง Method ที่คลาสนั้นๆ จำเป็นต้องมีแล้วและนั่นก็ทำให้คลาสทั้งสองของเราเป็นไปตามหลัก ISP เรียบร้อยแล้ว 🙂

ทีนี้ลองกลับมาดูคลาส Driver  ของเรากันครับ เนื่องจากทั้ง ToyotaAltis  และ ToyotaIQ  นั้น Implement CarInterface  ทั้งคู่แต่เพราะการเติมพลังงานของทั้งสองคลาสนั้นไม่เหมือนกัน ทำให้เราต้องเช็คประเภทของคลาสก่อนการเรียก Method ดังนี้

แต่…การใช้วิธีการเช็คประเภทของคลาสเพื่อเรียก Method นั้นเป็นการฝ่าฝืนหลัก Open Closed Principle (OCP) เพราะถ้าในอนาคตเรามีคลาสรถยนต์ใหม่เช่น ToyotaHydrogen  ซึ่งใช้การเติมพลังงานเป็นไฮโดรเจนทำให้เราต้องเพิ่มการเช็คเข้าไปเรื่อยๆ ดังนั้นสิ่งที่ผมจะทำก็คือการเพิ่ม ControllableInterface เข้าไป

และให้คลาส ToyotaAltis  และ ToyotaIQ  Implement และรวม Method ที่ใช้สำหรับในการควบคุมรถยนต์เข้าไปใน Method control()

และเราสามารถกลับมาแก้คลาส Driver  ได้ดังนี้

ทำให้เมื่อเรามีรถยนต์ประเภทใหม่ สิ่งที่ต้องทำก็คือการให้คลาสใหม่นั้น Implement ControllableInterface  นั่นเอง โดยที่เราไม่ต้องแก้ไขคลาส Driver  เลย

บทสรุป

หลักการนี้ค่อนข้างที่มีความคล้ายกับหลัก SRP นั่นก็คือการออกแบบ Interface นั้นก็ต้องกำหนดหน้าที่และความรับผิดชอบให้มีเพียงอย่างเดียวเช่นเดียวกับคลาส นั่นก็จะทำให้เรากำจัด Method ที่คลาสไม่จำเป็นต้องใช้งานออกไปได้

อ้างอิง

  1. https://laracasts.com/series/solid-principles-in-php/episodes/4
  2. https://en.wikipedia.org/wiki/Interface_segregation_principle
  3. http://www.oodesign.com/interface-segregation-principle.html
  4. http://www.toyota-global.com/innovation/environmental_technology/electric_vehicle/
  5. https://leanpub.com/laravel
prapat