Take the following examples, which have been abbreviated:

BasicButton:

public class BasicButton
{
    private var m_fOnClick:Function;

    public function BasicButton(pOnClick:Function)
    {
        m_fOnClick = pOnClick;
    }

    .
    .
    .
        // when the button has been clicked:
        m_fOnClick();
    .
    .
    .
}

DirectionalButton:

public final class DirectionalButton extends BasicButton
{
    private var m_eDirection:int;

    private var m_fOnClick:Function;

    public function DirectionalButton(pDirection:int, pOnClick:Function)
    {
        m_eDirection = pDirection;
        m_fOnClick = pOnClick;
        super(onClick);
    }

    private function onClick():void
    {
        m_fOnClick(m_eDirection);
    }
}

Is messing with the callback's parameter list like this a violation of the Liskov Substitution Principle? I know the constructors don't violate it, according to the way the industry generally interprets that principle, but whether messing with the callback's parameter list constitutes a mutation of a common output or whatever seems to be a little less clear.

On the one hand, both classes use a function called pOnClick that is called each time they're clicked on, and the instantiating code is able to pass in whichever function it wants to be referred to by pOnClick. On the other hand, since constructors tend to be abstracted from LSP, these two pOnClick parameters in the two constructors could be interpreted as referring to very different things.

Even if the two pOnClick parameters are interpreted as two separate inputs, there's still some ambiguity as to how much the subclasses's pOnClick effectively overwrites or destroys the superclass's (in a strictly virtual, publicly exposed sense), and how much it instead simply passes - in a very virtual sense - the equivalent of null to the superclass's still existent pOnClick.

It's a little tough to find the exact words for what I'm describing, but in general, where does LSP lie in this? Is this a violation? If so, can it be remedied by simply rewriting DirectionalButton.onClick as follows?

private function onClick():void
{
    try
    {
        m_fOnClick(m_eDirection);
    }
    catch (e:Error)
    {
        m_fOnClick(); // This is not how I would set this up in real life.
    }
}

Related posts

Recent Viewed