Open/Closed Principle (OCP) คือหลักการที่ว่า "Software entities (classes, modules, functions) ควรเปิดให้ขยาย (Open for extension) แต่ปิดต่อการแก้ไข (Closed for modification)"
หมายความ: เมื่อต้องการเพิ่มฟังก์ชันใหม่ ควรเพิ่มโค้ดใหม่ (เช่น สร้างคลาสใหม่) แทนที่จะแก้ไขโค้ดเดิมที่ทำงานอยู่แล้ว
ตัวอย่าง: ก่อนใช้ OCP (Violation)
public class Rectangle
{
public int Width { get; set; }
public int Height { get; set; }
}
public class Circle
{
public double Radius { get; set; }
}
// ปัญหา: ทุกครั้งเพิ่ม Shape ใหม่ ต้องแก้ไข CombinedAreaCalculator
public class CombinedAreaCalculator
{
public double Area(object[] shapes)
{
double area = 0;
foreach (var shape in shapes)
{
if (shape is Rectangle r)
area += r.Width * r.Height;
else if (shape is Circle c)
area += c.Radius * c.Radius * Math.PI;
// ถ้าเพิ่ม Triangle ต้องมาแก้ if-else ที่นี่!
}
return area;
}
}
ตัวอย่าง: หลังใช้ OCP (Compliant)
// 1. Abstract Base Class / Interface
public abstract class Shape
{
public abstract double Area();
}
// 2. Concrete Implementations
public class Rectangle : Shape
{
public int Width { get; set; }
public int Height { get; set; }
public override double Area() => Width * Height;
}
public class Circle : Shape
{
public double Radius { get; set; }
public override double Area() => Radius * Radius * Math.PI;
}
// 3. เพิ่ม Shape ใหม่ได้โดยไม่แก้ Calculator
public class Triangle : Shape
{
public double Base { get; set; }
public double Height { get; set; }
public override double Area() => 0.5 * Base * Height;
}
// 4. Calculator ปิดต่อการแก้ไข เปิดต่อการขยาย
public class CombinedAreaCalculator
{
public double Area(Shape[] shapes)
{
double area = 0;
foreach (var shape in shapes)
{
area += shape.Area(); // เรียก Polymorphism
}
return area;
}
}
ประโยชน์
- ลดความเสี่ยงการทำให้โค้ดเดิมเสีย (Regression)
- รองรับการเพิ่มฟีเจอร์ใหม่ได้ง่าย
- โค้ดอ่านง่าย รักษาได้ง่าย (Maintainable)
- สอดคล้องกับ Polymorphism และ Abstraction
เทคนิคอื่นๆ
- ใช้ Strategy Pattern สำหรับอัลกอริทึมที่เปลี่ยนแปลงได้
- ใช้ Decorator Pattern สำหรับเพิ่มพฤติกรรมโดยไม่แก้คลาสเดิม
- ใช้
interfaceแทน Abstract Class หากไม่ต้องการ Base Implementation