物件導向概念中的抽像是一種僅定義類別必須具有的基本面向的實踐。從本質上講,類別必須是不完整且不精確的,以便我們可以透過子類別對特殊性進行建模。由此產生了子類別、母類和繼承的概念。
繼承是類別之間關係的表示,其中一個類別擴展另一個類別以繼承父類別的行為。
SOLID 是一個縮寫詞,代表物件導向程式設計的五個基本原則,由 Robert C. Martin(鮑伯大叔)提出。在這裡您可以閱讀有關他的文章的更多資訊。
這些原則旨在改進程式碼的結構和維護,使其更加靈活、可擴展且更易於理解。這些原則可以幫助程式設計師創建更有組織的程式碼、劃分職責、減少依賴、簡化重構過程並促進程式碼重複使用。
縮寫中的「O」代表「開/閉原則」。 Bob叔叔用來定義這個原則的一句話是:
「類別必須對擴充開放,但對修改關閉」
根據這個原則,我們必須開發一個應用程序,確保我們以通用的方式編寫類別或模組,以便每當您覺得需要擴展類別或物件的行為時,您不需要更改類別本身。這裡的擴充可以理解為程式的新增或變更。
目的是允許添加新功能而無需更改現有程式碼。這可以最大限度地減少引入錯誤的風險並使程式碼更易於維護。
假設您有一個 DiscountCalculator 類別來計算產品折扣。最初,我們有兩個產品類別:電子產品和服裝。讓我們從不應用 OCP(開閉原則)開始:
class Product { private String name; private double price; public Product(String name, double price) { this.name = name; this.price = price; } public String getName() { return name; } public double getPrice() { return price; } } class DiscountCalculator { public double calculateDiscount(Product product) { if (product.getName().equals("Electronics")) { return product.getPrice() * 0.9; // 10% de desconto } else if (product.getName().equals("Clothing")) { return product.getPrice() * 0.8; // 20% de desconto } return product.getPrice(); } } public class Main { public static void main(String[] args) { Product electronics = new Product("Electronics", 100); Product clothing = new Product("Clothing", 50); DiscountCalculator calculator = new DiscountCalculator(); System.out.println(calculator.calculateDiscount(electronics)); // 90 System.out.println(calculator.calculateDiscount(clothing)); // 40 } }
class Product { private _name: string; private _price: number; constructor(name: string, price: number) { this._name = name; this._price = price; } public get name() { return this.name }; public set name(value: string) { this.name = value }; public get price() { return this.price }; public set price(value: number) { this.price = value }; } class DiscountCalculator { public calculateDiscount(product: Product): number { if (product.name === 'Electronics') { return product.price * 0.9; // 10% de desconto } else if (product.name === 'Clothing') { return product.price * 0.8; // 20% de desconto } return product.price; } } const electronics = new Product('Electronics', 100); const clothing = new Product('Clothing', 50); const calculator = new DiscountCalculator(); console.log(calculator.calculateDiscount(electronics)); // 90 console.log(calculator.calculateDiscount(clothing)); // 40
封裝違規:每次新的產品類型需要不同的折扣時,都需要修改calculateDiscount方法,包括在if中新增新的條件。
維護困難:如果方法成長了太多的if/else或開關,它將變得難以維護和測試。
引入錯誤的風險:對方法的變更可能會將錯誤引入依賴該方法的程式碼的其他部分。
現在,讓我們透過重構程式碼來應用開放/封閉原則,以允許在不修改現有程式碼的情況下添加新類型的折扣。
class Product { private String name; private double price; public Product(String name, double price) { this.name = name; this.price = price; } public String getName() { return name; } public void setName(String name) { this.name = name; } public double getPrice() { return price; } public void setPrice(double price) { this.price = price; } } interface DiscountStrategy { double calculate(Product product); } class ElectronicsDiscount implements DiscountStrategy { @Override public double calculate(Product product) { return product.getPrice() * 0.9; // 10% de desconto } } class ClothingDiscount implements DiscountStrategy { @Override public double calculate(Product product) { return product.getPrice() * 0.8; // 20% de desconto } } class NoDiscount implements DiscountStrategy { @Override public double calculate(Product product) { return product.getPrice(); } } class DiscountCalculator { private DiscountStrategy discountStrategy; public DiscountCalculator(DiscountStrategy discountStrategy) { this.discountStrategy = discountStrategy; } public double calculateDiscount(Product product) { return discountStrategy.calculate(product); } } public class Main { public static void main(String[] args) { Product electronics = new Product("Electronics", 100); Product clothing = new Product("Clothing", 50); Product books = new Product("Books", 30); DiscountCalculator electronicsDiscount = new DiscountCalculator(new ElectronicsDiscount()); DiscountCalculator clothingDiscount = new DiscountCalculator(new ClothingDiscount()); DiscountCalculator booksDiscount = new DiscountCalculator(new NoDiscount()); System.out.println(electronicsDiscount.calculateDiscount(electronics)); // 90 System.out.println(clothingDiscount.calculateDiscount(clothing)); // 40 System.out.println(booksDiscount.calculateDiscount(books)); // 30 } }
class Product { private _name: string; private _price: number; constructor(name: string, price: number) { this._name = name; this._price = price; } public get name() { return this.name }; public set name(value: string) { this.name = value }; public get price() { return this.price }; public set price(value: number) { this.price = value }; } interface DiscountStrategy { calculate(product: Product): number; } class ElectronicsDiscount implements DiscountStrategy { calculate(product: Product): number { return product.price * 0.9; // 10% de desconto } } class ClothingDiscount implements DiscountStrategy { calculate(product: Product): number { return product.price * 0.8; // 20% de desconto } } class NoDiscount implements DiscountStrategy { calculate(product: Product): number { return product.price; } } class DiscountCalculator { private discountStrategy: DiscountStrategy; constructor(discountStrategy: DiscountStrategy) { this.discountStrategy = discountStrategy; } public calculateDiscount(product: Product): number { return this.discountStrategy.calculate(product); } } const electronics = new Product('Electronics', 100); const clothing = new Product('Clothing', 50); const books = new Product('Books', 30); const electronicsDiscount = new DiscountCalculator(new ElectronicsDiscount()); const clothingDiscount = new DiscountCalculator(new ClothingDiscount()); const booksDiscount = new DiscountCalculator(new NoDiscount()); console.log(electronicsDiscount.calculateDiscount(electronics)); // 90 console.log(clothingDiscount.calculateDiscount(clothing)); // 40 console.log(booksDiscount.calculateDiscount(books)); // 30
如果我們需要添加新功能或行為而不必如此深入地修改現有程式碼庫,那麼應用開放/封閉原則至關重要。事實上,隨著時間的推移,我們發現實際上不可能避免 100% 更改程式碼庫,但可以減少插入新功能所需更改的程式碼總量。
這個原則使得程式碼更能適應變化,無論是滿足新的需求還是修正錯誤。
以上是Typescript 和 Java 中的開閉原則應用的詳細內容。更多資訊請關注PHP中文網其他相關文章!