背景
現在、デバイスによって送信および受信されるobjectがある状況にあります。このメッセージには、次のようないくつかの構成要素があります。
public void ReverseData()
public void ScheduleTransmission()
ScheduleTransmission
メソッドは、呼び出されるたびにReverseData
メソッドを呼び出す必要があります。ただし、ReverseData
を外部から呼び出す必要がある場合があります(オブジェクトの場所から名前空間の外側にを追加する必要があります)。アプリケーションでインスタンス化されます。
「受信」については、データを元に戻すために、ReverseData
がobject_received
イベントハンドラーで外部から呼び出されることを意味します。
質問
オブジェクトが独自のパブリックメソッドを呼び出すことは、一般的に許容されますか?
これは受け入れられるだけでなく、拡張機能を許可する場合は特に推奨されます。 C#でクラスの拡張をサポートするには、以下のコメントに従って、メソッドに仮想フラグを設定する必要があります。ただし、ReverseData()をオーバーライドしてScheduleTransmission()の動作を変更したときに誰かが驚かないように、これを文書化することをお勧めします。
本当にそれはクラスのデザインにかかっています。 ReverseData()は、クラスの基本的な動作のように聞こえます。他の場所でこの動作を使用する必要がある場合は、おそらく他のバージョンの動作を望まないでしょう。 ScheduleTransmission()に固有の詳細がReverseData()にリークしないように注意する必要があります。それは問題を引き起こします。しかし、あなたはすでにこれをクラスの外で使用しているので、おそらくすでにそれを熟考しているでしょう。
もちろんです。
メソッドの可視性は、クラス外または子クラス内のメソッドへのアクセスを許可または拒否することのみを目的としています。 public、protected、privateメソッドは常にクラス自体の内部で呼び出すことができます。
パブリックメソッドの呼び出しに問題はありません。あなたの質問のイラストは、2つのパブリックメソッドを持つことがまさにあなたがすべきことである状況の完璧な例です。
ただし、次のパターンには注意してください。
メソッドHello()
は、次のようにWorld(string, int, int)
を呼び出します。
_Hello()
{
this.World("Some magic value here", 0, 100);
}
_
このパターンは避けてください。代わりに、 オプションの引数 を使用します。オプションの引数を使用すると、発見しやすくなります。_Hello(
_と入力した呼び出し元は、デフォルト値でメソッドを呼び出すことができるメソッドがあることを必ずしも認識しません。オプションの引数も自己文書化されています。 World()
は、実際のデフォルト値が何であるかを呼び出し元に示しません。
メソッドHello(ComplexEntity)
は、次のようにWorld(string, int, int)
を呼び出します。
_Hello(ComplexEntity entity)
{
this.World(entity.Name, entity.Start, entity.Finish);
}
_
代わりに、 overloads を使用してください。同じ理由:発見しやすさ。呼び出し元は、IntelliSenseを介してすべてのオーバーロードを一度に確認し、適切なものを選択できます。
メソッドは、実質的な値を追加せずに、他のパブリックメソッドを呼び出すだけです。
考え直してください。この方法が本当に必要ですか?それとも削除して、呼び出し元にさまざまなメソッドを呼び出させますか?ヒント:メソッドの名前が正しくない、または見つけるのが難しい場合は、おそらく削除する必要があります。
メソッドは入力を検証してから、他のメソッドを呼び出します。
_Hello(string name, int start, int end)
{
if (name == null) throw new ArgumentNullException(...);
if (start < 0) throw new OutOfRangeException(...);
...
if (end < start) throw new ArgumentException(...);
this.World(name, start, end);
}
_
代わりに、World
はパラメーター自体を検証するか、プライベートにする必要があります。
何かが公開されている場合、いつでもどのシステムからも呼び出される可能性があります。あなたもそれらのシステムの1つになることができない理由はありません!
高度に最適化されたライブラリでは、Java.util.ArrayList#ensureCapacity(int)
に記述されているイディオムをコピーする必要があります。
ensureCapacity
は公開されていますensureCapacity
には、必要なすべての境界チェックやデフォルト値などがあります。ensureCapacity
呼び出しensureExplicitCapacity
ensureCapacityInternal
は非公開ですensureCapacityInternal
は、すべての入力がクラスの内部から取得されるため、最小限のエラーチェックしかありません。ensureCapacityInternal
ALSOはensureExplicitCapacity
を呼び出しますensureExplicitCapacity
もプライベートですensureExplicitCapacity
にはnoエラーチェックがありますensureExplicitCapacity
は実際の作業を行いますensureExplicitCapacity
は、ensureCapacity
とensureCapacityInternal
以外ではどこからも呼び出されませんこのようにして、信頼できるコードは、その入力が適切であることがわかっているため、特権(より高速)のアクセスを取得します。信頼できないコードは、その完全性を検証して攻撃したり、デフォルトを提供したり、その他の方法で不正な入力を処理したりするために、特定の厳密さを通過します。どちらも実際に機能する場所に誘導します。
ただし、これは、JDKで最もよく使用されるクラスの1つであるArrayListで使用されます。あなたのケースがそのレベルの複雑さと厳密さを必要としない可能性は非常に高いです。要するに、すべてのensureCapacityInternal
呼び出しがensureCapacity
呼び出しに置き換えられたとしても、パフォーマンスは本当に非常に優れています。これは、おそらく十分に検討した後にのみ行われるマイクロ最適化です。
いくつかの良い答えはすでに与えられており、オブジェクトにも他のメソッドからそのパブリックメソッドを呼び出すことができるということにも同意します。ただし、注意が必要な設計上の注意点が若干あります。
パブリックメソッドには、通常、「オブジェクトを一貫した状態にして、賢明なことを行い、オブジェクトを(場合によっては異なる)一貫した状態にしておく」という規約があります。ここで「一貫性がある」とは、たとえば、List<T>
のLength
がそのCapacity
以下であり、0
からLength-1
までのインデックスの要素を参照してもスローされないことを意味します。 。
ただし、オブジェクトのメソッド内では、オブジェクトが不整合な状態にある可能性があるため、パブリックメソッドの1つを呼び出すと、そのような可能性を考慮して記述されていないため、非常に間違った動作をする可能性があります。したがって、他のメソッドからパブリックメソッドを呼び出す予定がある場合は、それらのコントラクトが「オブジェクトをある状態で取り、何か賢明なことを行い、オブジェクトを(おそらく異なる)のままにします(一貫性がない可能性があります。ただし、最初の状態は一貫していませんでした)状態」。