これの特定のケースを扱った私が投稿した他の2つの質問があります:
Liskov Substitution Principleは、類似した密接に関連するコールバックに追加の引数を渡すサブクラスのどこにありますか?
スーパークラスのコンストラクターのパラメーターリストと一致すると、コンストラクター内でnullのデフォルト値がnull以外の値として扱われ、LSPに違反しますか?
しかし、これらは私を一般的なケースで少し失ったようなものにしました。これらの質問に対する回答から得た基本的な要約は次のとおりです。
リスコフの置換原則はコンストラクターには適用されません。建設後のみ適用されます。パラメータリストは必要に応じて変更でき、一致するパラメータに非常に異なる動作を示すようにすることもできます。
このルールの例外は、コールバックが基本クラスとスーパークラスの両方のコンストラクターに渡され、後で設定できない場合、通常の状況では、サブクラスのバージョンに下位互換性がなければならないことです。スーパークラスのバージョンで。これは、通常の状況では、外部コードが同じように動作する状態に入ることができないためです。
この声明は必ずしもそれ自体と矛盾するわけではありませんが、それは近づいていますが、それでも中途半端なきめ細かい点にすぎません。したがって、この時点で、コンストラクター、特にパラメーターリストを具体的に扱うLSPのサブプリンシパルについて質問することをお勧めします。
ここでのLSPの一般的なアプリケーションは何ですか?
例
次の例を考えてみましょう。これは特定の特定のポイントのみを示しています(この質問はまだ一般的なケースに関するものであり、この例ではありません)。
BasicButton:
public class BasicButton extends Sprite
{
private var m_fOnClick:Function;
private var m_fOnPress:Function;
private var m_fOnRelease:Function;
private var m_iColorPressed:uint;
private var m_iColorReleased:uint;
public function BasicButton(pColorPressed:uint, pColorReleased:uint, pOnClick:Function
= null, pOnPress:Function = null, pOnRelease:Function = null)
{
m_iColorPressed = pColorPressed;
m_iColorReleased = pColorReleased;
m_fOnClick = pOnClick;
m_fOnPress = pOnPress;
m_fOnRelease = pOnRelease;
drawBackground(pColorReleased);
}
private function drawBackground(pColor:uint):void
{
// completely fill the entire rectangular area of the button with one solid color
}
.
.
.
// when the button has been pressed:
if (m_fOnPress)
{
m_fOnPress();
}
.
.
.
}
DirectionalButton:
// This class illustrates several different points.
public final class DirectionalButton extends BasicButton
{
private var m_eDirection:int;
private var m_fOnPress:Function;
// Multiple parameters are omitted. Two are just uint configurations to decide a color
// with, and one is a callback that, if a non-null value had been included, would have
// interacted directly with outside code. Furthermore the pOnPress callback is treated
// differently throughout this class. Finally, pOnPress and pOnRelease are no longer
// optional.
public function DirectionalButton(pDirection:int, pOnPress:Function,
pOnRelase:Function)
{
m_eDirection = pDirection;
m_fOnClick = pOnClick;
// pOnPress is nullified; the superclass won't even try to call it.
// The colors are hard-coded.
super(0x858585, 0xCCCCCC, null, onPress, pOnRelease);
addArrowSprite(pDirection);
}
private function addArrowSprite(pDirection:int):void
{
// Add a new Sprite instance as a child, which will take the form of an arrow
// pointing in the specified direction, using a different color than the
// background. Whereas the you could always assume that the superclass maintained
// one color throughout at all times, this assumption will now be broken in the
// subclass. That means that, depending on how you interpret things, the
// background color specified in the superclass's constructor uses either differing
// or equivalent behavior.
}
private function onPress():void
{
m_fOnPress(m_eDirection); // pOnPress from before has had its parameter
// list interfered with. Also it is now assumed to be
// non-null.
}
}
この例はまだコンストラクターのパラメーターのみを扱っており、通常のパブリック関数などは扱っていないことに注意してください。さらに、コンストラクターに提供できる、いくつかの異なるいわゆる「プロパティ」がありますが、後で構成する方法はありません。
これらの種類のケースを処理する場合でも、さまざまなタイプのケースを処理する場合でも、コンストラクター、特にパラメーターリストに関するLSPルールは何ですか?
使用している言語によって異なります。
リスコフの置換原則(以下、LSP)の非公式な定義を見てみましょう。
基本型を使用できる場所であればどこでも、サブタイプのインスタンスを使用できるはずです。
これは、コンストラクターに接線方向にのみ影響します。 LSPは特に気にしませんhowインスタンスが作成され、一度作成されると、Niceを再生します。コンストラクターは、インスタンスが使用されたときにニースを再生する場合に明らかに影響を与える可能性がありますが、それはそれらの動作に影響を与える他のオブジェクトの状態と実際には違いはありません。
ただし、さらにいくつかの難解言語では、型(およびそのコンストラクター)をオブジェクトのように扱うことができます。この種のコンテキストでコンストラクターの動作が異なると、LSPに違反しますが、実際のクラスインスタンスではなく、型オブジェクトに違反します。