开放-封闭原则(OCP)
開放-封閉原則(The Open-Close Principle)
軟件實體(類、模塊、函數等)應該是可以擴展的,但是不可以修改的。兩個特征
1、對于擴展是開放的(Open for extension);
2、對于更改是封閉的(Close for modification)。
關鍵是抽象
既不開放又不封閉的Client
? ? ? ? Client類和Server類都是具體類。Client類使用Server類。如果我們希望Client對象使用另外一個不同的服務器對象,那么就必須把Client類中使用Server類的地方更改為新的服務器類。
Strategy 模式:既開放又封閉的Client
? ? ? ? Client需要實現一些功能,可以使用ClientInterface接口去描述那些功能。子類可以選擇它們的方式去實現這個接口。這樣,就可以通過創建ClientInteface的新的子類的方式去擴展、更改Client的行為。
? ? ? ? Why?把接口命名為ClientInterface,而非AbstractServer。因為抽象類和Client的關系更緊密。
Shape 應用程序
1、違反OCP
? ? ? ? drawAllShapes()不符合OCP,因為它對于新的形狀類型的添加不是封閉的。每添加一種新的形狀類型,都必須要更改這個函數。
public enum ShapeTpye {CIRCLE, SQUARE }public class Shape {ShapeType itsType; }public class Circle extends Shape {ShapeType itsType;double itsRadius;Point itsCenter; }public class Square extends Shape {ShapeType itsType;double itsSide;Point itsTopLeft; }//----------------------drawAllShapes--------------------- public void drawAllShapes(ShapePointer list[], int n) {int i;for (int i=0; i<n; i++) {Shape s = list[i];switch (s.itsType) {case SQUARE:drawSquare((Square)s);break;case CIRCLE:drawCircle((Circle)s);break;}}}2、遵循OCP
????????drawAllShapes()符合OCP,對它的改動是增加新的模塊,以及為了能夠實例化新類型而圍繞main的改動。
public interface Shape {public void draw(); }public class Square implements Shape {public void draw() {// 業務細節...} }public class Circle implements Shape {public void draw() {// 業務細節...} }//----------------------drawAllShapes--------------------- public void drawAllShape(List<Shape> list) {for(Shape s : list) {s.draw();} }3、預測變化與“合適”的結構
? ? ? ? 假設我們要求所有的圓必須在正方形之前繪制,drawAllShapes()無法對這種變化做到封閉。
? ? ? ? 無論模塊是多么的“封閉”,都會存在一些無法對之封閉的變化。不存在對所有情況都合適的模型。既然不可能完全封閉,那么就必須有策略地對待這個問題。設計人員必須對他設計的模型應該對哪種變化封閉做出選擇。他必須先猜測出最有可能發生變化種類,然后構造抽象來隔離那些變化。
? ? ? ? 遵循OCP的代價也是昂貴的。創建正確的抽象是要花費時間和精力的。同時,那些抽象也增加了軟件設計的復雜性。因而,我們希望把OCP的應用限定在可能會發生的變化上。
應對之道
1、只受一次愚弄
? ? ? ? 諺語:“愚弄我一次,應該羞愧的是你;再次愚弄我,應該羞愧的是我。”這意味著在我們最初編寫代碼時,假設變化不會發生。當變化發生時,我們就創建抽象來隔離以后同類變化。
2、刺激變化
? ? ? ? 如果我們決定接受第一顆子彈,那么子彈到來的越早越好、越快就對我們越有利。
首先編寫測試——迫使系統可測試,構建了使系統可測試的抽象。
使用很短的迭代周期進行開發
在加入基礎結構前就開發特性,并經常性地把那些特性展示給涉眾。
首先開發最重要的特性
盡早地、經常性地發布軟件
使用抽象獲得顯式封閉
public interface Shape extends Comparable<Shape> {public void draw();public boolean precedes(Shape s); }public class Circle implements Shape {// 根據對象類型排序...public boolean precedes(Shape s) {if (s instanceof Square) {return true;}return false;}public int compare(Shape s1, Shape s2) {if (s1.precedes(s2)) {return 1;}return -1;} }public void drawAllShapes(List<Shape> list) {sort(list);for (Shape s : list) {s.draw();} }表格驅動法獲取封閉性
public class Shape {private static final Class<Shape>[] typeOrderTable = new Class[]{Circle.class, Square.class};public void draw() {//...}public boolean precedes(Shape s) {Class thisType = this.getClass();Class argType = s.getClass();boolean done = false;int thisOrder = -1;int argOrder = -1;for (int i=0; !done; i++) {Class tableEntity = typeOrderTable[i];if (tableEntity.equals(thisType)) {thisOrder = i;}if (tableEntity.equeals(argType)) {argOrder = i;}if (thisOrder >= 0 && argType >= 0) {done = true;}}return thisOrder < argOrder;}}總結
以上是生活随笔為你收集整理的开放-封闭原则(OCP)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: BigDecimal 运用示例 与 De
- 下一篇: Linux 编译 没有path,编译li