รูปแบบการออกแบบกลยุทธ์
สมมติว่าเรามีแอปพลิเคชันที่ให้ลูกค้าชำระค่าสินค้าหรือรับบริการ
แอปพลิเคชันมีวิธีการชำระเงินมากกว่า 1 วิธี ลูกค้าสามารถใช้เงินสด บัตรวีซ่า หรือกระเป๋าเงิน เราสามารถทำได้ดังนี้
public class Customer {
public void pay(String paymentType) {
if (StringUtils.isEmpty(paymentType)) {
throw new RuntimeException("please add payment method");
}
// pay according to payment type
if (paymentType.equalsIgnoreCase("cash")) {
// pay in cash steps ( Algorithm )
} else if (paymentType.equalsIgnoreCase("visa")) {
// use the visa for payment steps ( Algorithm )
} else if (paymentType.equalsIgnoreCase("wallet")) {
// use the wallet for payment steps ( Algorithm )
} else {
throw new RuntimeException(paymentType + "payment type is not available");
}
}
}
public class Client {
public static void main(String[] args) {
Customer customer = new Customer();
customer.pay("cash");
}
}
ไม่จริง
- หากคุณต้องการเพิ่มวิธีการชำระเงินใหม่ คุณต้องเปลี่ยนคลาสนี้ และทำให้การออกแบบของคุณไม่ยืดหยุ่นสำหรับการเปลี่ยนแปลงใหม่ใดๆ การใช้งานนี้ถือว่าละเมิดหลักการออกแบบ SOLID ข้อหนึ่งซึ่งก็คือ: “ เอนทิตีซอฟต์แวร์ควรเปิดอยู่ เพื่อขยายแต่ปิดเพื่อแก้ไข ”
- ตรรกะส่วนใหญ่ในคลาสนี้ไม่ได้ใช้ เมื่อลูกค้าเลือกประเภทการชำระเงินแล้ว ดังนั้นหากลูกค้าต้องการชำระเป็นเงินสด รหัสที่ใช้จัดการวีซ่าและกระเป๋าเงินจะไม่ถูกใช้
- ตามที่คุณเห็นในการออกแบบนี้ คุณจะต้องจัดการกับอินพุตประเภทการชำระเงินที่เป็นไปได้ทั้งหมด แม้ว่าจะไม่สมเหตุสมผล เช่น ประเภทการชำระเงินที่เป็นโมฆะ หรือประเภทการชำระเงินที่ว่างเปล่า และคุณสามารถจำกัดให้ลูกค้าเลือกประเภทการชำระเงินที่ถูกต้องได้อย่างง่ายดาย โดยใช้รูปแบบกลยุทธ์
เรามีประเภทการชำระเงินสามประเภท และในแต่ละกรณีมีการใช้งานที่แตกต่างกัน ดังนั้นเราจึงมีพฤติกรรมแบบหนึ่ง"จ่าย"ด้วยวิธีการที่แตกต่างกัน ดังนั้นจะเกิดอะไรขึ้นหากเรานำสิ่งที่แตกต่างออกไปและจัดไว้ในคลาสที่แยกจากกันและใช้อินเทอร์เฟซทั่วไปสำหรับพฤติกรรมทั่วไป .
ให้เราสร้างส่วนต่อประสานที่เรียกว่าการชำระเงิน จะมีวิธีการแบบนามธรรม และวิธีการชำระเงินทุกวิธีมีระดับที่ชัดเจนซึ่งใช้อินเทอร์เฟซการชำระเงินลูกค้าจะมีอินเทอร์เฟซการชำระเงินเป็นตัวแปร "องค์ประกอบการใช้งาน" และวิธีการประเภทจะขึ้นอยู่กับทางเลือกของลูกค้า
public interface Payment {
void pay();
}
public class CashPayment implements Payment {
@Override
public void pay() {
// pay in cash steps ( Algorithm )
}
}
public class VisaPayment implements Payment {
@Override
public void pay() {
// use the visa for payment steps ( Algorithm )
}
}
public class WalletPayment implements Payment {
@Override
public void pay() {
// use the wallet for payment steps ( Algorithm )
}
}
public class Customer {
private Payment payment;
public Customer(Payment payment) {
this.payment = payment;
}
public void setPaymentType(Payment payment) {
this.payment = payment;
}
public void pay() {
payment.pay();
}
}
public class Client {
public static void main(String[] args) {
Customer customer = new Customer(new VisaPayment());
customer.pay();
// you can change the payment type at runtime
customer.setPaymentType(new CashPayment());
customer.pay();
}
}
![](https://post.nghiatu.com/assets/images/m/max/724/1*Tspu6n75yqFdYPbQPDicPw.png)
หลักการออกแบบ
จากการสนทนาก่อนหน้านี้ เราสามารถสรุปหลักการออกแบบได้สี่ประการ:
- ออกแบบสำหรับส่วนต่อประสานไม่ใช่เพื่อการใช้งาน
- สรุปสิ่งที่แตกต่างออกไป
- เอนทิตีซอฟต์แวร์ควรเปิดเพื่อขยาย แต่ปิดเพื่อแก้ไข
- ใช้องค์ประกอบเหนือการสืบทอด
คำจำกัดความของหนังสือสำหรับรูปแบบกลยุทธ์คือ: กำหนดกลุ่มของอัลกอริทึม สรุปแต่ละกลุ่ม และทำให้สามารถใช้แทนกันได้ กลยุทธ์ช่วยให้อัลกอริทึมแตกต่างจากไคลเอ็นต์ที่ใช้งาน
ในตัวอย่างของเรา กลุ่มของอัลกอริทึมคือวิธีการชำระเงิน และเราได้สรุปวิธีการชำระเงินแต่ละวิธีไว้ในคลาสย่อยที่เป็นรูปธรรม และสามารถใช้แทนกันได้โดยลูกค้าที่สามารถเลือกประเภทการชำระเงินใดก็ได้แม้ในขณะรันไทม์ อัลกอริทึมจะแยกออกจากลูกค้าและลูกค้า …. และนั่นคือรูป แบบกลยุทธ์