“software entities (classes, modules, functions, etc.) should be open for extension, but closed for modification”
Untuk mengimplement OCP, sebelumnya kode kita harus SRP – lihat pada tulisan SOLID Prinsiples – S-Single Responsibility, sehingga kita dapat mengindentifikasi dan memisahkan behavior yang berubah kedalam berbagai class. Output dari OCP adalah sekumpulan class yang memiliki behavior yang sama tapi dengan implementasi yang berbeda-beda. Perhatikan potongan kode program di bawah ini.
public class DiscountService { private const int GOLD = 1; private const int SILVER = 2; private double _totalSales; public DiscountService(double TotalSales) { _totalSales = TotalSales; } private int _custType; public int CustType { get { return _custType; } set { _custType = value; } } public double GetDiscount(int CustTpe) { if (_custType == GOLD) { return _totalSales - 100; } else if (_custType == SILVER) { return _totalSales - 50; } return _totalSales; } }
Masalah timbul ketika kita akan menambahkan beberapa tipe customer lain, maka akan sangat banyak kondisi “IF” di dalam kode program. Menambahkan kondisi “IF” baru artinya kita mengubah class CustomerService dan itu melanggar prinsip Close for modification.
Lantas bagaimana caranya mengimplementasikan prinsip Open for extension? Yaitu dengan menggunakan inheritance (lewat parent classnya) atau abstraksi (bisa menggunakan abstract class ataupun interface).
public interface ICustomer { string Name { get; } double GetDiscount(double TotalSales); }
Kemudian kita buat beberapa class konkrit untuk implementasi interface ICustomer di atas.
public class GoldCustomer : ICustomer { public string Name { get { return "Gold"; } } public double GetDiscount(double TotalSales) { return TotalSales - 100; } } public class SilverCustomer : ICustomer { public string Name { get { return "Silver"; } } public double GetDiscount(double TotalSales) { return TotalSales - 50; } }
Kemudian mari kita refactor kode program class DiscountService di atas sehingga jika ingin menambah tipe customer lagi, tidak perlu mengubah implementasi dari class DiscountService.
public class DiscountService { private readonly ICustomer _discount; private double _totalSales; public DiscountService(double TotalSales, ICustomer discount) { _totalSales = TotalSales; _discount = discount; } public virtual double GetDiscount() { return _discount.GetDiscount(_totalSales); } }
class Program { static void Main(string[] args) { double totalSales = 1000; DiscountService discountService; var listCustomer = new List(); listCustomer.Add(new GoldCustomer()); listCustomer.Add(new SilverCustomer()); foreach (var customer in listCustomer) { discountService = new DiscountService(totalSales, customer); Console.WriteLine("Customer Type: " + customer.Name); Console.WriteLine("Total after discount : " + discountService.GetDiscount()); Console.WriteLine("----------------------"); } Console.ReadKey(); } }
Sekarang kita bisa menambahkan 1 jenis customer lagi, tanpa harus mengubah code pada class Discount Service.
listCustomer.Add(new PlatinumCustomer());
Saya baru sadar, Open closed principle selalu kerja bareng dengan Dependency injection ya. Elemen OD dari SOLID muncul bersamaan.