Метод toString объекта и принцип подстановки Лискова

Каждый класс, прямо или косвенно, наследует от Object учебный класс.

Object Класс, среди прочих, имеет важный метод, чаще всего переопределяемый: toString,

Вопрос в том, не приведет ли переопределение этого метода к нарушению принципа подстановки Лискова в отношении Object учебный класс?

Я сделаю пример.

public class Main
{
    public static void main(String[] args)
    {
        Object o = new Object();
        String s = o.toString();
        if (s.indexOf('@') > -1) {
            System.out.println("OK");
        } else {
            System.out.println(":-(");
        }
    }
}

public class MyClass
{
    private int x;

    public string toString()
    {
        return Integer.toString(x);
    }
}

Очевидно, если я заменю new Object() с new MyClass() поведение системы меняется.

2 ответа

Решение

Ну, это дело вкуса. Object почти не имеет гарантированных свойств. Так что нарушать особо нечего.

Если вы говорите, что возвращение имени класса является таким свойством, которое может быть нарушено, то, конечно, подкласс не должен это менять. Но чтение документации Object.toString() показывает, что такой гарантии нет:

Возвращает строковое представление объекта. В общем случае метод toString возвращает строку, которая "представляет собой текст" этого объекта.

Так что я не вижу здесь нарушения LSP.

LSP не говорит, что подкласс должен вести себя точно так же, как суперкласс. Это сделало бы подклассы совершенно бесполезными. Требуется только, чтобы подклассы соответствовали спецификации суперкласса.


Единственное, что можно упомянуть, это то, что Object обеспечивает бессмысленный метод toString для каждого объекта. Более сложный дизайн мог бы поместить это в интерфейс.

Я думаю, что этот выбор дизайна - просто компромисс, принятый другими языками, такими как.NET.

Принцип подстановки Лискова требует только совместимости интерфейса. Это не говорит ничего изобилующего поведения. Так например

public interface Text {
    String value();
}

public class SimpleText implements Text {

    private final String value;

    public SimpleText(String value) {
        this.value = value;
    }

    @Override
    public String value() {
        return this.value;
    }
}

public class NumberText implements Text {

    private final Number number;

    public NumberText(Number number) {
        this.number = number;
    }

    @Override
    public String value() {
        return String.format("%.3f", this.number.doubleValue());
    }
}

Вам не важны детали реализации, поэтому вы можете обменяться ими следующим образом:

//We care only about value() method, not it's specific implementation
Text text = new SimpleText("text");
text.value();
text = new NumberText(44);
text.value();

Обратите внимание, что если ваша реализация вызовет какое-либо исключение, она нарушит LSP, поскольку Object.toString() не генерирует никаких исключений.

Другие вопросы по тегам