首頁 >Java >java教程 >Java中開放封閉原則的詳解

Java中開放封閉原則的詳解

黄舟
黄舟原創
2017-08-09 14:10:442428瀏覽

定義:軟體實體(類別、模組、函數等)應該是可以擴充的,但不可修改。對於擴展是開放的,對於更改是封閉的。關鍵是抽象,將一個功能的通用部分和實作細節部分清晰的分開。

這裡要求我們寫程式要有抽象的概念。什麼是抽象?指由實體抽離出概念的思考過程。就是從眾多的對像中抽離出共同的本質的特徵。在寫程式的過程中,需要抽象類別的地方,只需要抓住這個類別的本質功能,不要老是想著它在這個工程中的具體功能。

我們繼續看開放封閉原則,這個原則要求,將一個功能的共用部分和實作部分清晰地分開。因為在最初搭建架構的時候你不能預測到所有將要發生的變化,那麼這個類別也就不是一塵不變的,隨著在各個模組中具體實現的時候,你發現抽象的類別適合這個功能,但是對另一個功能又不適合。那麼是否要返回去修改抽象類別呢?這個代價是很大的,需要重新全盤思考,還要調整具體細節。如果程式還沒發布還好一些,一旦程式發布了,那麼回傳修改抽象類,影響將會更大。所以在開始抽象的時候就要防止這樣的現象發生,要遵循開放封閉原則。抽象類別、介面是一種標準,在程式中一旦定義好,就不能輕易去修改,需求有變化,怎麼辦呢?可以擴充這個接口,重寫方法,或是繼承後增加新的方法,但一定不要去修改。

下面用兩個例子來說明開放封閉原則。

1、連接資料庫為例。

例如在程式中用到的不同類型的資料庫連接,Access和Oracle。直接連接如下:


class ConnectAccess 
{ 
  public string ConnectString() 
  { 
    string dataPath = "数据库路径"; 
    return string.Format("Provider=Microsoft.Jet.OLEDB.4.0;Data Source={0};Persist Security Info=True;Jet OLEDB:Database Password={1}", dataPath, "密码"); 
  } 
} 
class ConnectOracle 
{ 
  public string ConnectString() 
  { 
    return @"server=localhost;database=命名空间;uid=用户名;pwd=密码"; 
  } 
}

調用


#
static void Main(string[] args) 
 { 
   //连接Access 
  ConnectAccess connAccess = new ConnectAccess(); 
 
  OleDbConnection accessConnection = new OleDbConnection(connAccessConnectString()); 
 
   //连接Oracle 
  ConnectOracle connOracle = new ConnectOracle(); 
 
  OracleConnection oracleConnection = new OracleConnection(connOracleConnectString()); 
 }

這樣每次都要去考慮OleDbConnection的參數到底用哪一個。下面修改一下。抽像一個介面。


interface ConnectDataBase 
{ 
  string ConnectString(); 
} 
 
class ConnectAccess : ConnectDataBase 
{ 
  #region ConnectDataBase 成员 
 
  public string ConnectString() 
  { 
    string dataPath = "数据库路径"; 
 
    return stringFormat("Provider=MicrosoftJetOLEDB0;Data Source={0};Persist Security Info=True;Jet OLEDB:Database Password={1}", dataPath, "密码"); 
  } 
 
  #endregion 
} 
 
class ConnectOracle : ConnectDataBase 
{ 
  #region ConnectDataBase 成员 
 
  public string ConnectString() 
  { 
    return @"server=localhost;database=命名空间;uid=用户名;pwd=密码"; 
  } 
 
  #endregion 
}

呼叫


#
static void Main(string[] args) 
{ 
  ConnectDataBase conn = null; 
 
  //连接Access 
  conn = new ConnectAccess(); 
 
  OleDbConnection accessConnection = new OleDbConnection(connConnectString()); 
 
  //连接Oracle 
  conn = new ConnectOracle(); 
 
  OracleConnection oracleConnection = new OracleConnection(connConnectString()); 
}

改過後,只要關心conn用哪一個類實例化,就可以了。不過大家可能看到,由於Oracle的連線必須OracleConnection,可能優勢不容易看出來。

2、基本型別作為方法參數為例。

一般的設計原則之所以強調方法參數盡量避免基本類型,原因正在於此。比較如下兩個方法定義:


//定义1  
bool Connect(string userName, string password, string wifiAddress, int port) 
{ 
  return false; 
}


#
//定义2  
bool Connect(Account account) 
{ 
  return false; 
}


public class Account 
{ 
  public string UserName 
  { 
    get; 
    set; 
  } 
  public string Password 
  { 
    get; 
    set; 
  } 
  public string WifiAddress 
  { 
    get; 
    set; 
  } 
  public int Port 
  { 
    get; 
    set; 
  } 
}

比較而言,定義2多了一個Account類別的定義,Connect()方法明顯更加穩定。如果Connect()方法wifiAddress發生改變,定義1必須修改該方法的接口,對應的,所有調用Connect()方法的對像都會受到影響;而定義2只需要修改Account類,由於Connect()方法的接口保持不變,而對於Connect()方法的呼叫者並不需wifiAddress,這樣的修改就完全不會影響呼叫者,進而降低需求變化帶來的影響。

總之開放封閉原則最關鍵的是抽象,但是也並不是說一旦抽象介面、類別確定就一定不能修改。只是,我們在抽象的時候就要全面思考,爭取做到不用修改,一旦需求有變化,只要在實現的時候有變動。當然,需求是千變萬化的,一旦需要改動抽象的部分,那麼只要前面嚴格遵循了這個原則,影響也會小得多。當然如果修改了,一定要進行單元測試,凡是用到的地方都要測試正確。

以上是Java中開放封閉原則的詳解的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn