Переопределить атрибуты - PullRequest
13 голосов
/ 14 июля 2011

Когда вы переопределяете метод, вы должны сохранить сигнатуру метода и не можете уменьшить его видимость. Теперь я попробовал, что происходит, когда я делаю это с атрибутами. Я был удивлен - это работает! Смотри сам:

public class A {

    public Integer myAttribute;

}

public class B extends A {

    public String myAttribute;

}

public class Main {

        public static void main(String[] args) {
        B b = new B();
        b.myAttribute = "myString";
        ((A) b).myAttribute = 1337;
        System.out.println(b.myAttribute);
        System.out.println(((A)b).myAttribute);
    }

}

Таким образом, можно написать атрибут в подклассе с тем же именем атрибута, что и в суперклассе, но вы можете использовать разные видимость (модификатор) и тип. Поэтому я бы сказал, что атрибуты в суперклассе и подклассе практически полностью независимы друг от друга.

Теперь, если вы действительно используете одно и то же имя атрибута в суперклассе и подклассе, вы фактически скрываете атрибут суперкласса. При доступе к атрибуту с использованием подкласса вы получаете атрибут подкласса. Но атрибут суперкласса тоже есть! Вы должны выполнить приведение, чтобы получить доступ к атрибуту суперкласса извне. Изнутри ключевое слово «super» должно быть полезным.

Вопрос 1: Теперь у вас есть два разных атрибута с одинаковыми именами. Разве это не ломается LSP ?

Почему я пришел к этой детали так: Я экспериментирую с самописной основой персистентности. Я хочу прочитать полное внутреннее состояние объекта и сохранить это состояние. Я читаю все значения атрибута с помощью рефлексии, начиная с подтипа и проходя через суперклассы. Теперь, если в суперклассе и подклассе есть два атрибута с одинаковыми именами, я должен запомнить класс, который объявляет атрибут, чтобы иметь возможность сопоставлять значения атрибутов с правильными атрибутами и восстанавливать состояние объекта.

Вопрос 2: Любые другие идеи, как бороться с этой деталью? Вопрос 3: Как другие персистентные фреймворки обрабатывают эту деталь?

Я никогда не видел эту деталь в использовании. Может быть, написание двух атрибутов с одним и тем же именем немного уродливо, но это возможно, и любой персистентный фреймворк может столкнуться с этим. Возможно, есть ситуации, когда этот метод может быть полезен.

Заранее.

Ответы [ 5 ]

5 голосов
/ 14 июля 2011

ORM обычно используют стандарт javabeans, который определяет «свойства».Свойства определяются методом чтения и / или записи, а не полем, которое они читают / пишут.В 99% случаев свойствами являются field + getter & setter, но это не обязательно должно быть так.И ORM читает эти свойства и обнаруживает только те поля, которые имеют методы получения и установки.Поскольку методы переопределяются, а не затеняются, проблема исчезла.

Это скорее проблема инкапсуляции, чем нарушение LSP.Доступ к полю не подвержен полиморфизму, поэтому, если у вас есть поле Foo foo = new FooSubclas(); foo.field the value of the Foo`, это означает, что поведение не изменится.

2 голосов
/ 14 июля 2011

Вы не можете переопределить атрибут, только скрыть его.Это буквально называется скрытием полей в учебнике .Подробнее об этом блоге .

Q1: Нет, он не нарушает LSP, любая ссылка на A a = new B(); a.myAttribute все равно будет ссылаться на A.myAttribute, а не на B.myAttribute.

Q2: Я бы постарался избежать этого, но если вам нужно, вы все равно можете получить доступ к A.myAttribute из B, используя ключевое слово super.myAttribute.

Q3: Я думаю, что C # позволяетто же самое, они используют base вместо super, но у меня нет под рукой компилятора C #, и документация по скрытию полей в C # скудна.

2 голосов
/ 14 июля 2011

Вопрос 1. Он не нарушает LSP, потому что переменные-члены не являются полиморфными.

1 голос
/ 14 июля 2011

Вопрос 2. Сериализация / десериализация только через геттеры / сеттеры.

Вопрос 3: См. Ответ 2.

1 голос
/ 14 июля 2011

Вопрос 1: LSP равен behavioral subtyping, и я бы сказал, что наличие двух участников с одинаковым именем само по себе не меняет поведение.

Вопрос 2: Определите его (вам нужно отсканироватьиерархия классов в любом случае) и не допустить этого.

...