Workshop: สร้างระบบ Payment Gateway - ตอนที่ 4: กำหนด Interface: PaymentGatewayInterface
สวัสดีครับ! ในบทที่แล้ว เราได้สร้างโครงสร้างพื้นฐานของโปรเจกต์ Payment Gateway ของเรากันไปแล้ว ในบทนี้ เราจะมาสร้างสิ่งที่สำคัญมาก ๆ นั่นคือ Interface ครับ Interface เปรียบเสมือนสัญญาที่กำหนดว่าคลาสที่ต้องการทำงานเป็น Payment Gateway จะต้องมีคุณสมบัติอะไรบ้าง ทำให้โค้ดของเรามีความยืดหยุ่นและง่ายต่อการบำรุงรักษามากขึ้น
ทำไมต้องใช้ Interface?
ก่อนที่เราจะเริ่มสร้าง Interface กัน เรามาทำความเข้าใจกันก่อนว่าทำไมเราถึงต้องใช้ Interface ในการสร้าง Payment Gateway ของเรา
- Abstraction: Interface ช่วยให้เราสามารถซ่อนรายละเอียดการทำงานภายในของแต่ละ Payment Gateway (เช่น Stripe หรือ PayPal) ได้ ทำให้เราสามารถเรียกใช้งาน Payment Gateway ได้โดยไม่ต้องรู้ว่าแต่ละอันทำงานอย่างไร
- Loose Coupling: Interface ช่วยลดการพึ่งพากันระหว่างคลาส ทำให้เราสามารถเปลี่ยน Payment Gateway ได้ง่าย โดยไม่ต้องแก้ไขโค้ดในส่วนอื่น ๆ ของระบบ
- Polymorphism: Interface ช่วยให้เราสามารถใช้ Payment Gateway ต่าง ๆ ได้อย่างยืดหยุ่น โดยไม่ต้องกังวลเรื่องชนิดของ Payment Gateway ที่เรากำลังใช้งาน
ลองนึกภาพว่าคุณมีปลั๊กไฟหลายแบบ (เช่น แบบกลม, แบบแบน) แต่เครื่องใช้ไฟฟ้าของคุณมีช่องเสียบแบบเดียว (เช่น ช่องเสียบแบบแบน) ถ้าคุณไม่มี Adapter (Interface) คุณจะไม่สามารถใช้ปลั๊กไฟแบบกลมกับเครื่องใช้ไฟฟ้าของคุณได้ Interface จึงเป็นเหมือน Adapter ที่ช่วยให้ปลั๊กไฟ (Payment Gateway) ต่าง ๆ สามารถใช้งานร่วมกับเครื่องใช้ไฟฟ้า (ระบบของเรา) ได้อย่างราบรื่น
สร้าง Interface: PaymentGatewayInterface
ตอนนี้เรามาเริ่มสร้าง Interface ของเรากันเลยครับ ในโปรเจกต์ของเรา ให้สร้างไฟล์ใหม่ชื่อว่า `PaymentGatewayInterface.php` ในโฟลเดอร์ `src` (ถ้ายังไม่มีโฟลเดอร์ `src` ให้สร้างขึ้นมาก่อนนะครับ)
เปิดไฟล์ `PaymentGatewayInterface.php` แล้วใส่โค้ดต่อไปนี้:
<?php
namespace App;
interface PaymentGatewayInterface
{
public function charge(float $amount, string $token): string;
public function refund(string $transactionId, float $amount): bool;
}
มาดูกันทีละส่วนว่าโค้ดนี้หมายถึงอะไร:
namespace App;: กำหนด namespace ให้กับ Interface ของเรา เพื่อป้องกันชื่อซ้ำกับ Interface อื่น ๆinterface PaymentGatewayInterface: ประกาศ Interface ชื่อ `PaymentGatewayInterface`public function charge(float $amount, string $token): string;: กำหนด method ชื่อ `charge` สำหรับการชำระเงิน Method นี้รับค่า$amount(จำนวนเงิน) และ$token(ข้อมูลบัตรเครดิตหรือข้อมูลการชำระเงินอื่น ๆ) และคืนค่าเป็นstringซึ่งเป็น Transaction IDpublic function refund(string $transactionId, float $amount): bool;: กำหนด method ชื่อ `refund` สำหรับการคืนเงิน Method นี้รับค่า$transactionId(รหัสของการทำรายการที่ต้องการคืนเงิน) และ$amount(จำนวนเงินที่ต้องการคืน) และคืนค่าเป็นboolซึ่งบอกว่าการคืนเงินสำเร็จหรือไม่
อธิบายเพิ่มเติมเกี่ยวกับ parameters และ return types:
float $amount: ระบุว่า parameter$amountต้องเป็นตัวเลขทศนิยม (floating-point number) เช่น 10.50, 100.00string $token: ระบุว่า parameter$tokenต้องเป็นข้อความ (string) Token นี้อาจเป็นข้อมูลที่ได้จาก Stripe.js หรือ PayPal SDKstring $transactionId: ระบุว่า parameter$transactionIdต้องเป็นข้อความ (string) Transaction ID นี้เป็นรหัสที่ใช้ระบุการทำรายการแต่ละครั้งbool: ระบุว่า method จะคืนค่าเป็น boolean (true หรือ false)
กรณีใช้งานจริงและข้อผิดพลาดที่พบบ่อย
กรณีใช้งานจริง:
สมมติว่าเรามีระบบร้านค้าออนไลน์ เมื่อลูกค้าต้องการชำระเงิน เราจะเรียกใช้ method charge ของ Payment Gateway ที่เราเลือก (เช่น Stripe หรือ PayPal) โดยส่งจำนวนเงินและ token ที่ได้จากระบบ Payment Gateway นั้น ๆ ไปให้ จากนั้นเราจะได้รับ Transaction ID กลับมา ซึ่งเราจะเก็บไว้ในฐานข้อมูลของเรา
เมื่อลูกค้าต้องการคืนสินค้า เราจะเรียกใช้ method refund ของ Payment Gateway โดยส่ง Transaction ID และจำนวนเงินที่ต้องการคืนไปให้ ถ้าการคืนเงินสำเร็จ Method จะคืนค่า true กลับมา
ข้อผิดพลาดที่พบบ่อย:
- ลืม implements Interface: คลาสที่ต้องการทำงานเป็น Payment Gateway จะต้อง `implements` Interface `PaymentGatewayInterface` ถ้าลืม จะทำให้เกิด error
- method signature ไม่ตรงกัน: method ที่ implements Interface จะต้องมีชื่อ, parameters, และ return type เหมือนกับที่กำหนดไว้ใน Interface ทุกประการ ถ้าไม่ตรงกัน จะทำให้เกิด error
- ไม่ได้จัดการ exception: การชำระเงินและการคืนเงินอาจเกิดข้อผิดพลาดได้ (เช่น บัตรเครดิตไม่ถูกต้อง, เงินในบัญชีไม่พอ) เราจะต้องจัดการ exception เหล่านี้อย่างเหมาะสม เพื่อให้ระบบของเราทำงานได้อย่างราบรื่น
ตัวอย่างการใช้งาน (ยังไม่ต้องทำตาม)
เพื่อให้เห็นภาพมากขึ้น ลองดูตัวอย่างการใช้งาน Interface (แต่ยังไม่ต้องทำตามนะครับ เราจะทำในบทต่อไป):
<?php
namespace App;
class StripePayment implements PaymentGatewayInterface
{
public function charge(float $amount, string $token): string
{
// โค้ดสำหรับการชำระเงินผ่าน Stripe
// ...
return 'stripe_transaction_id_123'; // คืนค่า Transaction ID
}
public function refund(string $transactionId, float $amount): bool
{
// โค้ดสำหรับการคืนเงินผ่าน Stripe
// ...
return true; // คืนค่า true ถ้าการคืนเงินสำเร็จ
}
}
ในตัวอย่างนี้ คลาส `StripePayment` `implements` Interface `PaymentGatewayInterface` ดังนั้นคลาสนี้จึงต้องมี method `charge` และ `refund` ตามที่กำหนดไว้ใน Interface
สรุป
ในบทนี้ เราได้เรียนรู้เกี่ยวกับการสร้าง Interface `PaymentGatewayInterface` ซึ่งเป็นสัญญาที่กำหนดว่าคลาสที่ต้องการทำงานเป็น Payment Gateway จะต้องมีคุณสมบัติอะไรบ้าง Interface ช่วยให้โค้ดของเรามีความยืดหยุ่นและง่ายต่อการบำรุงรักษามากขึ้น
ในบทต่อไป เราจะมาเริ่ม Implement Payment Gateway แต่ละตัวกัน โดยเริ่มจาก Stripe ครับ เตรียมตัวให้พร้อม!