Dove si trova generalmente il Principio di sostituzione di Liskov in diverse liste di parametri del costruttore?

1

Ci sono altre due domande che ho postato che trattano casi specifici di questo:

dove il Principio di sostituzione di Liskov si trova in una sottoclasse che passa argomenti extra a richiami simili, strettamente correlati?

Corrispondenza del parametro del costruttore della superclasse list, sta trattando un valore predefinito null come valore non nullo all'interno di un costruttore una violazione di LSP?

ma questi mi hanno lasciato un po 'perso nel caso generale. Un riassunto di base di ciò che ho ottenuto dalle risposte a queste domande è il seguente:

The Liskov Substitution Principle does not apply to constructors; it only applies post-construction. You can change parameter lists all you want, and you can even make matching parameters exhibit very different behaviors.

An exception to this rule is that if a callback is passed in to the constructor of both the base class and the superclass, and if it cannot be set at a later time, then the subclass's version, in normal situations, must be backwards-compatible with superclass's version. The reason for this is that, in normal situations, outside code cannot otherwise enter into a state in which it would behave in the same way.

Anche se questa affermazione non si contraddice necessariamente, si avvicina, ma solo su un punto a metà a grana fine. Quindi, a questo punto, è probabilmente una buona idea per me chiedere del sottoprincipio di LSP che si occupa specificamente dei costruttori, in particolare con i loro elenchi di parametri.

Qual è l'applicazione generale di LSP qui?

Esempio

Considera il seguente esempio, che illustra solo alcuni punti specifici (questa domanda riguarda comunque il caso generale, non questo esempio):

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.
    }
}

Ricorda che questo esempio riguarda solo i parametri dei costruttori, non con normali funzioni pubbliche o altro. Inoltre hai diverse cosiddette "proprietà" che sono suppliabili ai costruttori, ma che non hanno modo di essere configurate in seguito.

Che si tratti di casi di questo tipo o di diversi tipi di casi, qual è la regola LSP sui costruttori, specialmente con i loro elenchi di parametri?

    
posta Panzercrisis 21.01.2015 - 15:40
fonte

1 risposta

3

Dipende dalla lingua con cui stai lavorando.

Diamo un'occhiata alla definizione informale del Principio di sostituzione di Liskov (herafter LSP):

You should be able to use an instance of a subtype anywhere you could use the base type.

Questo influisce solo tangenzialmente sui costruttori. A LSP non interessa particolarmente come vengono create le istanze , solo che una volta create sono perfette. Ovviamente, i costruttori possono avere un impatto se le istanze suonano piacevoli se usate, ma ciò non è molto diverso dagli altri stati oggetto che influenzano il loro comportamento.

In alcuni altri linguaggi esoterici, i tipi (ei loro costruttori) possono essere trattati come oggetti. Avere i costruttori comportarsi diversamente in quel tipo di contesto sarebbe una violazione di LSP, ma degli oggetti di tipo, non delle istanze di classe effettive.

    
risposta data 21.01.2015 - 16:03
fonte