Can a standalone class be seen as violating the Liskov Substitution Principle

classliskov-substitution

Say we have the interface

interface IColoredSquare
{
    int GetSideLength();
    void SetSideLength(int length);
    string GetColor();
}

and I implement it like this

class ColoredSquare : IColoredSquare
{
    private int _length;
    private string _color;

    public Square(int length, string color)
    {
        _length = length;
        _color = color;
    }

    public int GetSideLength()
    {
        throw new ApplicationException("How dare you");
    }

    public void SetSideLength(int length)
    {
        _color = _color == "blue" ? "red" : "blue";
    }

    public string GetColor() 
    {
        return _color;
    }
}

So this violates the LSP in at least three different ways. The precondition on GetSideLength has been strengthened to the point it's unusable, the post condition on SetSideLength that the side length should be set has been weakened to the point of non-existence, and what should be invariant, the return value of GetColor, is getting randomly switched for no reason.

But this got me thinking, what really changes if we remove the interface? So we just have

class ColoredSquare
{
    // Same fields, constructor and methods as before
}

To my mind this still violates the LSP, even though it's no longer a proper subtype of anything (except for trivial things like object). After all even though it doesn't implement an interface it does expose one, namely

class ColoredSquare
{
    public int GetSideLength();
    public void SetSideLength(int length);
    public string GetColor();
}

and that's what people will actually program against. They don't (or at least shouldn't have to) go snooping around inside the code to see how to use the class. And this class fails to have pretty much any properties that the exposed interface promises, except the ones forced by the compiler to be true.

So, is it fair to say that this class violates the LSP? Or is this a misunderstanding of what the LSP is?

My uncertainty comes from the fact that every example I've ever seen has talked about interfaces or class inheritance. Never about stand-alone classes.

Best Answer

The Liskov substitution principle says:

If f is a formula such that f(x) is true for all objects x of type T, then f(y) should be true for all objects y of type S, which is a subtype of T.

In particular, this is trivially true, if you don't have subtypes of T.

Your class doesn't violate LSP, in fact, LSP is meaningless for it. Your class simply has confusing methods: either naming/description is wrong, or the logic is flawed. But LSP doesn't apply to it, because the core behind LSP is that you can use subtype S in place of base type T, and be sure it works the same way. Regardless of how good/bad that way is. In particular if I subclass your class, but I don't modify those functions, then it will satisfy LSP.

Related Topic