目錄
design pattern 以java 為例
開放封閉原則 (OCP: Open Closed Principle) 通常簡稱為 SOLID 原則中的 “O”。這個原則指出軟件實體(類、模塊、函數等)應該對擴展開放
,對修改封閉
。
實現方式
code 翻立 基礎資料 加設現在要做一個商品的filter, 並且依顏色形狀等做分類,我們會有基礎class
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 enum Color { RED, GREEN, BLUE }enum Size { SMALL, MEDIUM, LARGE, YUGE }class Product { public String name; public Color color; public Size size; public Product (String name, Color color, Size size) { this .name = name; this .color = color; this .size = size; } }
非OCP 設計原則,硬解 我們可以把每個條件去做比較,但可以而知隨著參數變多,條件變多,就會變成可怕的code
1 2 3 4 5 6 7 8 9 10 11 12 13 class ProductFilter { public Stream<Product> filterByColor (List<Product> products, Color color) { return products.stream().filter(p -> p.color == color); } public Stream<Product> filterBySize (List<Product> products, Size size) { return products.stream().filter(p -> p.size == size); } public Stream<Product> filterBySizeAndColor (List<Product> products, Size size, Color color) { return products.stream().filter(p -> p.size == size && p.color == color); } }
OCP 設計模式 interface 我們可以建立滿足條件及過濾的interface
1 2 3 4 5 6 7 8 interface Specification <T> { boolean isSatisfied (T item) ; }interface Filter <T> { Stream<T> filter (List<T> items, Specification<T> spec) ; }
實作 中間時做一個and 來做連接
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 class ColorSpecification implements Specification <Product> { private Color color; public ColorSpecification (Color color) { this .color = color; } @Override public boolean isSatisfied (Product p) { return p.color == color; } }class SizeSpecification implements Specification <Product> { private Size size; public SizeSpecification (Size size) { this .size = size; } @Override public boolean isSatisfied (Product p) { return p.size == size; } }class AndSpecification <T> implements Specification <T> { private Specification<T> first, second; public AndSpecification (Specification<T> first, Specification<T> second) { this .first = first; this .second = second; } @Override public boolean isSatisfied (T item) { return first.isSatisfied(item) && second.isSatisfied(item); } }
或是可以透過list 結合stream
1 2 3 4 5 6 class BetterFilter implements Filter <Product> { @Override public Stream<Product> filter (List<Product> items, Specification<Product> spec) { return items.stream().filter(p -> spec.isSatisfied(p)); } }
結果 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 class OCPDemo { public static void main (String[] args) { Product apple = new Product ("Apple" , Color.GREEN, Size.SMALL); Product tree = new Product ("Tree" , Color.GREEN, Size.LARGE); Product house = new Product ("House" , Color.BLUE, Size.LARGE); List<Product> products = List.of(apple, tree, house); ProductFilter pf = new ProductFilter (); System.out.println("Green products (old):" ); pf.filterByColor(products, Color.GREEN) .forEach(p -> System.out.println(" - " + p.name + " is green" )); BetterFilter bf = new BetterFilter (); System.out.println("Green products (new):" ); bf.filter(products, new ColorSpecification (Color.GREEN)) .forEach(p -> System.out.println(" - " + p.name + " is green" )); System.out.println("Large products:" ); bf.filter(products, new SizeSpecification (Size.LARGE)) .forEach(p -> System.out.println(" - " + p.name + " is large" )); System.out.println("Large blue items:" ); bf.filter(products, new AndSpecification <>( new ColorSpecification (Color.BLUE), new SizeSpecification (Size.LARGE) )) .forEach(p -> System.out.println(" - " + p.name + " is large and blue" )); } }
1 2 3 4 5 6 7 8 9 10 11 Green products (old): - Apple is green - Tree is green Green products (new): - Apple is green - Tree is green Large products: - Tree is large - House is large Large blue items: - House is large and blue
結論 這種做法可以有效地重新利用,避免過多的重複程式產生