定義: ソフトウェア エンティティ (クラス、モジュール、関数など) は拡張可能である必要がありますが、変更することはできません。拡張のために開かれ、変化のために閉じられます。重要なのは抽象化であり、機能の一般的な部分を実装の詳細から明確に分離します。
ここでは、コードを書くときに抽象的な概念を持つことが求められます。抽象化とは何ですか?実体から概念を抽象化する思考プロセスを指します。数多くの物体から共通の本質的な特徴を抽出することです。コードを記述するプロセスで抽象クラスが必要になる場合は、このクラスの本質的な機能を把握するだけでよく、このプロジェクトにおけるその特定の機能について常に考える必要はありません。
オープンとクローズの原則を見ていきましょう。この原則では、関数の共有部分と実装部分を明確に分離する必要があります。最初にアーキテクチャを構築するときに発生するすべての変更を予測することはできないため、このクラスを各モジュールに実装すると、抽象クラスがこの機能に適していることがわかりますが、実際はそうではありません。別の機能に適しています。それでは、抽象クラスに戻って変更しますか?このコストは非常に高く、特定の詳細を再考して調整する必要があります。プログラムがまだリリースされていない場合は、プログラムがリリースされた後に戻って抽象クラスを変更すると、より大きな影響が得られます。したがって、抽象化を開始するときは、この現象が起こらないようにして、オープンとクローズの原則に従う必要があります。抽象クラスとインターフェイスは標準であり、プログラムで一度定義すると、要件が変更された場合はどうすればよいでしょうか。このインターフェイスを拡張したり、メソッドを書き換えたり、継承後に新しいメソッドを追加したりできますが、変更しないでください。
オープンクローズの原則を説明するために 2 つの例を使用します。
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=密码"; } }
Call
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 }
Call
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. メソッドパラメータとしての基本型を例に挙げます。
これが、一般的な設計原則がメソッド パラメーターは可能な限り基本型を避ける必要があることを強調する理由です。次の 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 クラスの定義が 1 つ多くあり、Connect() メソッドの方が明らかに安定しています。 Connect() メソッドの wifiAddress が変更された場合、定義 1 はメソッドのインターフェイスを変更する必要があり、それに応じて Connect() メソッドを呼び出すすべてのオブジェクトが影響を受けますが、定義 2 は Account クラスを変更するだけで済みます。 Connect() メソッドは変更されず、Connect() メソッドの呼び出し元には wifiAddress が必要ないため、このような変更は呼び出し元にまったく影響を与えず、デマンドの変更による影響が軽減されます。
要するに、オープンとクローズの原則で最も重要なことは抽象化ですが、抽象インターフェイスとクラスが一度決定されたら、それらを変更してはいけないという意味ではありません。ただし、抽象化する場合は、包括的に考えて、要件が変更された場合は実装時に変更するだけで済むように努める必要があります。もちろん、ニーズは常に変化します。抽象的な部分を変更する必要がある場合でも、原則に厳密に従っている限り、影響ははるかに小さくなります。もちろん、変更する場合は単体テストを実行する必要があり、使用されるすべてのものを正しくテストする必要があります。
以上がJava のオープンとクローズの原則の詳細な説明の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。