OCP — หลักการ ความเปิดกว้างสำหรับการขยาย และความปิดสำหรับการแก้ไข

ผู้แต่ง: IT Sectr เผยแพร่เมื่อ: 2026-05-11 เวลาอ่าน: 9 นาที

OCP (Open/Closed Principle) เป็นหลักการที่สองของ SOLID ซึ่งกำหนดว่า: เอนทิตีซอฟต์แวร์ควรเปิดกว้างสำหรับการขยาย แต่ปิดสำหรับการแก้ไข หลักการนี้ ซึ่งคิดค้นโดย Bertrand Meyer ในปี 1988 ช่วยให้สามารถเพิ่มฟังก์ชันการทำงานใหม่โดยไม่ต้องเปลี่ยนโค้ดที่มีอยู่ ตามหนังสือของ Robert Martin Clean Architecture (2017) หลักการเปิดกว้าง ถูกนำไปใช้ผ่านนามธรรมและพหุนาม ช่วยลดความเสี่ยงของข้อผิดพลาดแบบถดถอย

ประเด็นสำคัญ

  • OCP — หลักการความเปิดกว้างสำหรับการขยายและความปิดสำหรับการแก้ไข
  • การขยาย ถูกนำไปใช้ผ่านนามธรรม อินเทอร์เฟซ และพหุนาม
  • การแก้ไข โค้ดที่มีอยู่เป็นสิ่งต้องห้าม — ฟังก์ชันการทำงานใหม่ถูกเพิ่มโดยไม่เปลี่ยนแปลงคลาสเก่า
  • พหุนาม — กลไกสำคัญของ OCP ในภาษาเชิงวัตถุ
  • การละเมิด OCP นำไปสู่การเปลี่ยนแปลงแบบลูกโซ่เมื่อเพิ่มข้อกำหนดใหม่

OCP (Open/Closed Principle) คืออะไร?

OCP (Open/Closed Principle) — หลักการความเปิดกว้างสำหรับการขยายและความปิดสำหรับการแก้ไข คลาส โมดูล และฟังก์ชันควรถูกออกแบบเพื่อให้สามารถเพิ่มพฤติกรรมใหม่ได้โดยไม่ต้องเปลี่ยนซอร์สโค้ดของพวกมัน การขยายทำได้ผ่านการสืบทอด องค์ประกอบ หรือการแทนที่การImplement อินเทอร์เฟซ

Bertrand Meyer ในหนังสือ Object-Oriented Software Construction (1988) อธิบาย OCP ครั้งแรกผ่านการสืบทอด: คลาสพื้นฐานยังคงไม่เปลี่ยนแปลง ในขณะที่คลาสย่อยขยายพฤติกรรมของมัน การตีความสมัยใหม่ของ OCP ที่เสนอโดย Robert Martin อาศัย พหุนามและอินเทอร์เฟซ: แทนที่จะใช้การสืบทอด จะใช้สัญญานามธรรมแทน

ความแตกต่างระหว่างแนวทางมีนัยสำคัญ การสืบทอดสร้างการเชื่อมโยงที่แน่นหนาระหว่างคลาสพื้นฐานและคลาสที่สืบทอด อินเทอร์เฟซและองค์ประกอบให้ความยืดหยุ่น: สามารถสลับการImplement ได้โดยไม่ต้องเปลี่ยนโค้ดไคลเอ็นต์ OCP สมัยใหม่ เกี่ยวกับนามธรรม ไม่ใช่การสืบทอด

พหุนามเป็นพื้นฐานของ OCP

OCP เชิงพหุนาม ใช้คลาสนามธรรมหรืออินเทอร์เฟซเพื่อกำหนดสัญญา โค้ดไคลเอ็นต์ทำงานกับนามธรรมโดยไม่รู้จักการImplement ที่เป็นรูปธรรม ฟังก์ชันการทำงานใหม่ถูกเพิ่มโดยการสร้างคลาสใหม่ที่Implement อินเทอร์เฟซเดียวกัน — โดยไม่ต้องเปลี่ยนแปลงโค้ดที่มีอยู่แม้แต่บรรทัดเดียว สิ่งนี้ทำให้ระบบทนทานต่อการเปลี่ยนแปลงและคาดเดาได้สำหรับการขยาย

ในการพัฒนาแอปพลิเคชันมือถือ แนวทางนี้แพร่หลาย: รูปแบบ Strategy ช่วยให้สามารถสลับอัลกอริทึม (การบีบอัดภาพ การแคช การตรวจสอบสิทธิ์) ผ่านอินเทอร์เฟซเดียว การเพิ่มกลยุทธ์ใหม่ไม่จำเป็นต้องเปลี่ยนโค้ดที่ใช้มัน

วิธีนำหลักการเปิดกว้างและปิดไปใช้

การImplement OCP เริ่มต้นด้วยการแยกพฤติกรรมที่เปลี่ยนแปลงได้ออกเป็นนามธรรม หากมีโครงสร้าง switch หรือห่วงโซ่ if-else ที่ตรวจสอบประเภทของออบเจ็กต์ในโค้ด — นี่คือสัญญาณให้ใช้ OCP แต่ละสาขาเงื่อนไขอาจต้องเพิ่มสาขาใหม่เมื่อขยาย

กระบวนการรีแฟคเตอริงภายใต้ OCP ประกอบด้วยสามขั้นตอน: ระบุ ด้านที่เปลี่ยนแปลงได้ (สิ่งที่สามารถขยายได้) แยกมันออกเป็นอินเทอร์เฟซหรือคลาสนามธรรม เขียนโค้ดไคลเอ็นต์ใหม่ให้ทำงานกับนามธรรมแทนคลาสที่เป็นรูปธรรม หลังจากนั้น ฟังก์ชันการทำงานใหม่จะถูกเพิ่มโดยไม่เปลี่ยนไคลเอ็นต์

คำชี้แจงสำคัญ: ความปิดสำหรับการแก้ไข ไม่ใช่สิ่งสัมบูรณ์ หากการเปลี่ยนแปลงข้อกำหนดส่งผลกระทบต่อนามธรรมหรือสัญญาเอง — การเปลี่ยนแปลงเป็นสิ่งที่หลีกเลี่ยงไม่ได้ OCP ป้องกันการเปลี่ยนแปลงในการImplement ไม่ใช่ในสัญญา การออกแบบที่ดีสันนิษฐานว่าสัญญามีความเสถียรและการImplement สามารถเปลี่ยนแปลงได้

เมื่อประเมินความเข้ากันได้ของ OCP ของสถาปัตยกรรม ควรดูที่ จุดขยาย แต่ละจุดที่นักพัฒนาเพิ่ม if-else หรือ switch สำหรับประเภทใหม่ — เป็นตัวเลือกสำหรับนามธรรม ระบบที่ออกแบบตาม OCP มีจุดขยายที่คาดเดาได้: อินเทอร์เฟซพร้อมเอกสารที่บอกว่า "Implement อินเทอร์เฟซนี้เพื่อเพิ่มประเภทใหม่" ใน Android รูปแบบ Factory คู่กับ ViewModelProvider.Factory เป็นตัวอย่างที่ชัดเจน — การเพิ่มประเภท ViewModel ใหม่ไม่จำเป็นต้องเปลี่ยนโรงงานที่มีอยู่

กลยุทธ์และรูปแบบสำหรับ OCP

รูปแบบที่มีประสิทธิภาพมากที่สุด สำหรับการปฏิบัติตาม OCP ในการพัฒนาแอปพลิเคชันมือถือประกอบด้วย Strategy, Template Method, Decorator และ Factory แต่ละรูปแบบแก้ปัญหาการขยายพฤติกรรมโดยไม่แก้ไขโค้ดที่มีอยู่ผ่านกลไกการออกแบบเชิงวัตถุที่แตกต่างกัน

Strategy ช่วยให้สามารถสลับอัลกอริทึมได้ทันทีผ่านอินเทอร์เฟซร่วม ในการพัฒนา iOS กลยุทธ์ถูกใช้สำหรับแอนิเมชันและการตรวจสอบฟอร์ม Template Method กำหนดโครงร่างของอัลกอริทึมในคลาสพื้นฐาน และคลาสย่อยเขียนทับขั้นตอน — เหมาะสำหรับหน้าจอที่มีโครงสร้างร่วมกันแต่เนื้อหาต่างกัน

Decorator เพิ่มพฤติกรรมให้กับออบเจ็กต์แบบไดนามิกโดยไม่เปลี่ยนคลาสของมัน ใน Android Decorator ถูกใช้สำหรับการห่อ Repository ด้วยชั้นแคชหรือบันทึก Factory Method สร้างออบเจ็กต์ผ่านอินเทอร์เฟซ ทำให้คลาสย่อยตัดสินใจได้ว่าจะInstance คลาสใด — พื้นฐานของการสร้างการพึ่งพาที่เข้ากันได้กับ OCP

การเลือกกลยุทธ์สำหรับโปรเจกต์มือถือ

การเลือกรูปแบบ ขึ้นอยู่กับความเสถียรของพฤติกรรมที่กำลังขยาย Strategy เหมาะสมที่สุดเมื่ออัลกอริทึมถูกแทนที่ทั้งหมด Template Method — เมื่อโครงสร้างคงที่แต่ขั้นตอนเปลี่ยนแปลง Decorator — เมื่อการขยายควรโปร่งใสสำหรับไคลเอ็นต์ สำหรับสถานการณ์ส่วนใหญ่ใน Android และ iOS Strategy + การฉีดพึ่งพา ก็เพียงพอ

การประยุกต์ใช้รูปแบบเหล่านี้โดยไม่มี OCP เป็นไปได้ในทางเทคนิคแต่สูญเสียความหมาย OCP คือสิ่งที่อธิบายว่าทำไมเราถึงแนะนำระดับนามธรรมเพิ่มเติม: เพื่อให้ระบบสามารถเติบโตได้โดยไม่ต้องเขียนโค้ดที่มีอยู่ใหม่

ตัวอย่าง OCP ในแอปพลิเคชันมือถือ

ลองพิจารณา ตัวอย่าง Android ด้วยการประมวลผลการชำระเงิน หากไม่มี OCP ระบบการชำระเงินใหม่แต่ละระบบต้องมีการเปลี่ยนแปลงในคลาสตัวจัดการ หากมี OCP จะเพิ่มการImplement อินเทอร์เฟซใหม่โดยไม่ต้องแก้ไขโค้ดที่มีอยู่

kotlin
// การละเมิด OCP: switch ต้องการการแก้ไขเมื่อเพิ่มระบบใหม่
class BadPaymentProcessor {
    fun process(type: String) {
        when (type) {
            "card" -> // การประมวลผลบัตร
            "paypal" -> // การประมวลผล PayPal
        }
    }
}

// การออกแบบที่เข้ากันได้กับ OCP
interface PaymentMethod {
    fun pay(amount: Double)
}

class CardPayment : PaymentMethod {
    override fun pay(amount: Double) { }
}

class PayPalPayment : PaymentMethod {
    override fun pay(amount: Double) { }
}

// ระบบใหม่ — คลาสใหม่ โดยไม่เปลี่ยนโค้ดที่มีอยู่
class ApplePayPayment : PaymentMethod {
    override fun pay(amount: Double) { }
}

ตัวอย่าง iOS ด้วยการตรวจสอบฟิลด์ข้อความแสดงตรรกะเดียวกันผ่านโปรโตคอล Swift:

swift
// การตรวจสอบที่เข้ากันได้กับ OCP
protocol ValidationRule {
    func validate(_ input: String) -> Bool
}

struct EmailRule: ValidationRule {
    func validate(_ input: String) -> Bool {
        return input.contains("@")
    }
}

struct PhoneRule: ValidationRule {
    func validate(_ input: String) -> Bool {
        return input.count == 11
    }
}

// การเพิ่มกฎใหม่ไม่จำเป็นต้องเปลี่ยนโค้ดตัวตรวจสอบ
struct PasswordRule: ValidationRule {
    func validate(_ input: String) -> Bool {
        return input.count >= 8
    }
}

ข้อได้เปรียบสำคัญ ของ OCP ในตัวอย่างเหล่านี้: การเพิ่ม ApplePay หรือ PasswordRule ไม่จำเป็นต้องแก้ไขคลาสที่มีอยู่ โค้ดขยายในแนวนอน — ผ่านไฟล์ใหม่ ไม่ใช่โดยการเปลี่ยนไฟล์เก่า สิ่งนี้ลดความเสี่ยงของการถดถอยและเร่งการImplement ฟังก์ชันการทำงานใหม่

ข้อผิดพลาดทั่วไปเมื่อละเมิด OCP

การละเมิดที่พบบ่อยที่สุด คือโครงสร้าง switch หรือ when ตามประเภทของออบเจ็กต์ ทุกครั้งที่มีการเพิ่มประเภทใหม่ ต้องค้นหา switch เหล่านั้นทั้งหมดในโค้ดและเพิ่มสาขาใหม่ switch ที่พลาดเป็นบั๊กขณะรันไทม์ที่ยากต่อการตรวจพบในเวลาคอมไพล์

ในการพัฒนาแอปพลิเคชันมือถือ OCP ถูกละเมิดเมื่อใช้ คลาส enum ขนาดใหญ่ ที่มีเมธอดซึ่งขึ้นอยู่กับค่า enum การเพิ่มองค์ประกอบ enum ใหม่ต้องเปลี่ยนทุก switch ทั่วทั้งโปรเจกต์ ทางเลือกคือพหุนามผ่านอินเทอร์เฟซ โดยที่แต่ละประเภทImplement พฤติกรรมของตัวเอง

การละเมิดทั่วไปอีกอย่างคือ God Adapter: RecyclerView.Adapter (Android) หรือ UITableViewDataSource (iOS) ที่จัดการประเภทเซลล์ต่างกันผ่าน if-else แต่ละประเภทเซลล์ใหม่ต้องขยายอะแดปเตอร์ วิธีแก้คือ ViewHolder เชิงพหุนามที่มีเมธอด bind ร่วม โดยแต่ละประเภทเซลล์รับผิดชอบการเรนเดอร์ของตัวเอง

วิธีหลีกเลี่ยงการละเมิด OCP

มาตรการป้องกัน รวมถึง: หลีกเลี่ยง switch ตามประเภทเพื่อหันไปใช้พหุนาม ฉีดพึ่งพาผ่านอินเทอร์เฟซ และใช้รูปแบบ Factory เพื่อสร้างออบเจ็กต์ตามการกำหนดค่า การวิเคราะห์โค้ดเพื่อหา "สวิตช์ตามประเภท" เป็นส่วนบังคับของการตรวจสอบโค้ดในทีมที่เน้น OCP

การรีแฟคเตอริงการละเมิด OCP ที่มีอยู่ ทำผ่าน Replace Conditional with Polymorphism: แต่ละสาขาเงื่อนไขกลายเป็นคลาสแยกที่Implement อินเทอร์เฟซร่วมกัน โค้ดไคลเอ็นต์ถูกเขียนใหม่ให้ทำงานกับอินเทอร์เฟซ และการImplement ที่เป็นรูปธรรมถูกจัดหาผ่านโรงงานหรือคอนเทนเนอร์ DI

สิ่งสำคัญคือต้องเข้าใจว่า OCP และพหุนามไม่ได้แก้ปัญหาการขยายทั้งหมด หากเลือกสถาปัตยกรรมไม่ถูกต้อง การเพิ่มฟังก์ชันการทำงานใหม่จะต้องเปลี่ยนไม่เพียงแต่การImplement แต่ยังรวมถึงสัญญาด้วย สถาปัตยกรรมที่ดี คาดการณ์ทิศทางการขยายและวางนามธรรมตรงจุดเหล่านั้น การลงทุนใน OCP จะคุ้มค่ามากขึ้นเมื่อโปรเจกต์มีอายุยาวนานขึ้นและข้อกำหนดของโมดูลเฉพาะเปลี่ยนแปลงบ่อยขึ้น

คำถามที่พบบ่อย

OCP หมายความว่าไม่สามารถเปลี่ยนแปลงโค้ดได้เลยหรือไม่?

ไม่ OCP ห้ามการเปลี่ยนแปลงโค้ดที่มีอยู่เมื่อเพิ่มฟังก์ชันการทำงานใหม่ที่เกี่ยวข้องกับนามธรรมเดียวกัน การเปลี่ยนสัญญา การแก้ไขบั๊ก และการรีแฟคเตอริงไม่ใช่การละเมิด OCP — หลักการป้องกันการเปลี่ยนแปลงแบบลูกโซ่ระหว่างการขยาย

OCP เกี่ยวข้องกับรูปแบบ Strategy อย่างไร?

Strategy คือการImplement โดยตรงของ OCP อินเทอร์เฟซกลยุทธ์กำหนดสัญญา ไคลเอ็นต์ขึ้นอยู่กับนามธรรม และกลยุทธ์ที่เป็นรูปธรรมImplement พฤติกรรมที่เปลี่ยนแปลงได้ การเพิ่มกลยุทธ์ใหม่ไม่จำเป็นต้องเปลี่ยนไคลเอ็นต์ — นี่คือความเปิดกว้างสำหรับการขยายพร้อมความปิดสำหรับการแก้ไข

สามารถปฏิบัติตาม OCP โดยไม่มีอินเทอร์เฟซได้หรือไม่?

ได้ ผ่าน การสืบทอดและ Template Method: คลาสพื้นฐานกำหนดโครงร่างของอัลกอริทึมและคลาสย่อยเขียนทับขั้นตอน อย่างไรก็ตาม การสืบทอดสร้างการเชื่อมโยงที่แน่นหนาและยืดหยุ่นน้อยกว่าอินเทอร์เฟซ ในการพัฒนาสมัยใหม่ อินเทอร์เฟซและองค์ประกอบถือเป็นวิธีที่ต้องการในการImplement OCP

OCP ส่งผลต่อการทดสอบอย่างไร?

โค้ดที่เข้ากันได้กับ OCP ทำให้การทดสอบง่ายขึ้น: แต่ละการImplement อินเทอร์เฟซถูกทดสอบแยกกัน โค้ดไคลเอ็นต์ถูกทดสอบด้วยการImplement จำลอง ทำให้สามารถตรวจสอบตรรกะโดยไม่ผูกติดกับพฤติกรรมเฉพาะ การขยายระบบไม่จำเป็นต้องเขียนการทดสอบที่มีอยู่ใหม่

ควรพยายามทำให้ได้ OCP เสมอหรือไม่?

ไม่ OCP มีความชอบธรรมเมื่อการขยายฟังก์ชันการทำงานสามารถคาดเดาได้ สำหรับโค้ดที่เสถียรซึ่งไม่มีแผนจะขยาย นามธรรมเพิ่มเติมนั้นมากเกินไป YAGNI (You Ain't Gonna Need It) เป็นการถ่วงดุลที่ดีสำหรับ OCP: นามธรรมถูกนำเสนอเมื่อพฤติกรรมรูปแบบที่สองปรากฏขึ้น ไม่ใช่ล่วงหน้า

สรุป

  • OCP (Open/Closed Principle) — หลักการความเปิดกว้างสำหรับการขยายและความปิดสำหรับการแก้ไข
  • การขยาย ถูกนำไปใช้ผ่านอินเทอร์เฟซ พหุนาม และองค์ประกอบแทนการสืบทอด
  • Switch ตามประเภท — หลักการต่อต้านที่ละเมิด OCP และต้องเปลี่ยนแปลงทุกครั้งที่มีประเภทใหม่
  • Strategy และ Template Method — รูปแบบหลักสำหรับการปฏิบัติตาม OCP ในโปรเจกต์มือถือ
  • พหุนาม แทนที่โครงสร้างเงื่อนไขและทำให้โค้ดขยายได้โดยไม่ต้องแก้ไข
  • รีแฟคเตอริง การละเมิด OCP ทำผ่าน Replace Conditional with Polymorphism
  • YAGNI จำกัด OCP: นามธรรมถูกนำเสนอเมื่อการImplement ครั้งที่สองปรากฏขึ้น ไม่ใช่ล่วงหน้า

เราจะพัฒนาแอปพลิเคชันบนมือถือแบบครบวงจร

IT Sectr สร้างแอปพลิเคชัน iOS และ Android สำหรับสตาร์ทอัพและธุรกิจตั้งแต่ปี 2017 เราจะให้คำแนะนำและเสนอวิธีแก้ปัญหาที่ดีที่สุดแก่คุณ

ปรึกษาโครงการ

อ่านเพิ่มเติม