拡張可能なメソッドの書き込み
メソッドを拡張する前に、メソッドの公開されている機能と、メソッドが使用されるシナリオに拡張が与える影響を評価する必要があります。 たとえば、ビジネス シナリオによっては、テーブル レコードを初期化する拡張機能を有効にした場合に低リスクになりますが、固有の検証をスキップする拡張機能を有効にした場合にリスクが高くなります。 メソッドが他の機能拡張と並行して拡張される場合の影響を検討することもできます。
メソッドを拡張可能にすると、メソッドのシグネチャまたはロジックが変更された場合のユーザーへの潜在的な影響のため、メソッドのさらなる変更が制限されます。
拡張可能コードを作成するときに準拠するべきいくつかのガイドラインを次に示します。
簡単な方法を記述する : 1つの方法には、1つの責任のみを設定する必要があります。 これによりでは、メソッドの拡張が簡単になり、拡張がメソッドの特定の責任でのみ機能します。 単純な例として、クラス オブジェクトの構築および初期化を 2 つの異なるメソッドに保持します。
必要な情報のみを公開 : 追加する新しいクラス メンバまたはメソッドについては、「新しいクラス メンバまたはメソッドをプライベートに追加して、最小限のアクセス許可を与えます。
プライベート、保護された、パブリック、および最終的な明示的な : メソッドとクラスのフィールドについては、このアプローチによって、コードの任意の拡張が拡張ポイントに ガイド 使用されますが、拡張ユーザーが注意したり依存したりしない部分を完全に制御できます。
メソッド パラメータ
- このメソッドは、多くの場合長くなるため、リファクタリングする必要があります。 メソッド全体をクラスにリファクタリングするか、必要なパラメーターが少ないより小さいメソッドにメソッドを分割するかを検討してください。
- それ以外の場合、いくつかのパラメーターが必要なときは、パラメーターには多くの場合がクラスによって表すことができる一貫性があります。 クラスでこれらのパラメーターをカプセル化することにより、アプリケーション プログラミング インターフェイス (API) を後で中断せずに、拡張担当者が基準メソッドにパラメーターを追加しやすくなります。
切り替えブロック
メソッドの途中でブロックを切り替えないでください。 切り替えブロックは、拡張可能になるにはそれ自身のメソッドになければなりません。
ケース ブロックが長 、各ケース ブロックで1つのクラス/クラス階層にリファクタリングされるのが望みです。 例については、SalesLineCopyFromSource クラス階層を参照してください。
切り替えステートメントでは既定のブロックを回避してください。切り替えブロックを拡張不能にするメソッドを作成するためです。
切り替えステートメントの既定のブロックでスロー ステートメントを回避してください。切り替えステートメントを拡張不能にするスイッチを作成するためです。 既定のケースでのスローを処理する 1 つの方法は、拡張可能な個別のメソッドに切り替えブロックをリファクタリングすることです。 または、メソッド全体を交換可能にすることができます。
次の例では、findOrderHeaderDefault が交換可能です。
private Common findOrderHeader(boolean _forUpdate) { switch (this.InventTransType) { case InventTransType::Sales: return this.salesTable(_forUpdate); default: return this.findOrderHeaderDefault(_forUpdate); } } [Replaceable] protected Common findOrderHeaderDefault(boolean _forUpdate) { throw error(Error::wrongUseOfFunction(funcName())); }
[一 一方 、メソッドの ブロックを拡張することは難しくなるので、メソッドのブロック を してください。 理想的には、while ブロックのロジックは、拡張機能を有効にする別のメソッドに置く必要があります。
whileループ内のリファクタリング ロジック
再ファクタリング後のExtensible method
もし。。elseステートメント
- if ステートメントで条件を拡張できるようにするには、if 条件のロジックを別のメソッドに抽出します。
- 入れ子になった if..else ブロックは回避してください。いずれかのロジックでの変更がむずかしくなるためです。 この問題を解決するための 1 つの方法は、各条件および各ブロックのロジックを個別のメソッドにリファクタリングすることです。 この方法では、条件または各ブロックのロジックを拡張することができます。
- if..else ブロックが特殊化を処理する場合、ロジックをクラス階層に移動することを検討してください。 例については、SalesLineCopyFromSource を参照してください。
- 一部のシナリオでは、メソッドの "else" ブロックでのスロー (メソッドに if.. else のみある場合) によってメソッドが拡張不能になります。 else でのスローを処理する 1 つの方法は、スローの条件を個別のメソッドにリファクタリングすることです。
PrmIsDefault を使用しないように: メソッドが上書きまたはラップ可能な場合は、 super() or next()) すべてのパラメータを指定します。 したがって、prmIsDefault() は常に false を返します。
enumCntの使用を避 : コンパイル時に、このメソッドは、ユーザーが持っている値の数を数値列挙型します。 列挙が拡張されるか、後で拡張可能になった場合、コードを再コンパイルする必要があります。 代わりに DictEnum.values() を使用します。
メソッドの作成
- 拡張を簡単にするには、SysExtension フレームワークを使用します。
- ファクトリ メソッドでのスローを回避します。 この問題を解決するための 1 つの方法は、拡張できる別のメソッドにスローの条件を抽出することです。 詳細については、このリストの後方にあるスロー ステートメントのガイドラインを参照してください。
静的メソッド : 静的メソッドを追加の状態で拡張できません。 たとえば、メソッド拡張担当者は、パラメーター メソッドを使用して設定できるプロパティを導入できます。 この方法が可能な場合は必ず、代わりにインスタンス メソッドを使用します。
長いメソッドにロジックの一部を拡張する機能 : 方式全体をリファクタリングできないが、メソッドの拡張に参加させるのが目的の場合は、抽出メソッドの再ファクタリングを適用します。 新しい保護されたメソッドには単一の責任が必要であり、その責任を概念的かつ正確に説明する名前も必要です。 これにより、オーナーおよびすべての拡張担当者は互いに中断することがなくメソッドを使用できます。 たとえば、初期化、挿入、テーブル レコードの更新、またはクラスのインスタンス化および初期化は、小さいメソッドに抽出でき、それらの小さい各メソッドで拡張を有効にできます。 その後、元のメソッドがこれらの個々のメソッドを呼び出します。 したがって、このメソッドの呼び出し元は中断されません。
手書き : 拡張可能性がある既存の方法に追加される、拡張機能を拡張する場合があります。 拡張可能メソッドでスローの条件を追加することを検討してください。 これにより、拡張担当者はメソッドを利用でき、スローを取り除くことができます。
条件が保護されたメソッドに再ファクタリングされた場合
再ファクタリング後のExtensible method
2つのステートメントの作成、読み取り、更新、および削除 (何を行う)
- クエリを拡張可能にする必要のある状況でクエリ オブジェクトを使用します。 クエリを構築する保護されたメソッドを実装します。 さらに、結合されたデータ ソース、範囲、および選択フィールドを追加するために、複数の個別のメソッドを構築できます。 この方法では、クエリのさまざまな部分を個別に拡張できます。
- SysQueryInsertRecordSet を使用して、insert_recordset をクエリに変換します。
- select ステートメントではフィールド リストは避けてください。 この方法では、拡張することがなく、拡張担当者が追加のフィールドを取得できるようにすることができます。
- クエリ範囲で in キーワードを使用し、拡張担当者が値をさらにクエリ範囲に追加できるようにします。 この方法は特に、列挙値を持つクエリ範囲にお勧めします。