Наследование, нарушающее инкапсуляцию? - PullRequest
4 голосов
/ 19 февраля 2012

Люди говорят, что наследование нарушает инкапсуляцию, с чем я согласен.Они говорят, что делегирование лучше - хотя модификаторы в делегировании также могут быть публичными / защищенными.

Так является ли реальной причиной того, что наследование нарушает инкапсуляцию из-за эффекта "зацепки" модификаторов public / protected от суперкласса, подвергающегося воздействию любых новых классов, расширяющих текущий подкласс?

Ответы [ 4 ]

3 голосов
/ 19 февраля 2012

Да. Поскольку он предоставляет производному классу доступ к членам базового класса (в зависимости от того, какой язык и какой тип наследования), говорят, что он нарушает инкапсуляцию. ИМХО это только в том случае, если вы цепляетесь за инкапсуляцию в самых строгих терминах. ИМХО разумно сказать, что вы принимаете производный класс как расширение базы и, следовательно, связаны каким-то образом и не нарушаете инкапсуляцию. Пуристы не согласятся с этим.

Взгляните на http://www.ccs.neu.edu/research/demeter/papers/context-journal/node17.html и найдите «перерывы» для академического объяснения.

1 голос
/ 10 декабря 2016

Я думаю, что, с моей точки зрения, он ломается в случае добавления новых методов в базовый или суперкласс.Если A является подклассом B, даже если A не изменяется каким-либо образом, изменение в B может нарушить A.(Это называется эффектом Ripple)

Пример: предположим, что A переопределяет все методы в B, сначала проверяя входные аргументы в каждом методе ( по соображениям безопасности ).Если к B добавлен новый метод, а A не обновлен, новый унаследованный метод создаст дыру в безопасности.

Чтобы избавиться от ловушек в наследовании, используйте или используйте «Композицию» вместоНаследование, простая агрегация вместо наследования, ниже приведен пример:

Представьте себе два класса, Person и Employee.Вместо того, чтобы просить Employee наследовать от Person, вы можете составить Person внутри Employee и направить запросы на функциональность Person составному классу. Таким образом, мы все еще получаем преимущество от повторного использования Person класса.1026 *

Примечания:

  • Person класс может быть абстрактным классом ИЛИ

  • Person классможет быть protected внутри того же пакета, что и Employee

0 голосов
/ 16 декабря 2018

представьте:

class A {
    void foo(){
        ...
        this.bar();
        ...
    }
    void bar(){
        ...
    }
}

class B extends A {
    //override bar
    void bar(){
        ...
    }
}

class C {
    void bazz(){
        B b = new B();
        // which bar would be called?
        B.foo();
    }
}

Как вы видите в bazz метод, который будет вызываться bar?второй будет называться bar в классе B.но в чем здесь проблема?проблема в том, что метод foo в классе A не будет ничего знать о переопределении метода bar в классе B. Тогда ваши инварианты могут быть нарушены.потому что foo может ожидать единственное поведение метода bar в своем классе, а не что-то переопределяется.Эта проблема называется хрупкая проблема базового класса .

0 голосов
/ 19 февраля 2012

Это зависит от того, как мы проектируем наш класс. При разработке класса Мы должны помнить принцип Open-Closed . Когда мы говорим об инкапсуляции, мы говорим о модификации и когда мы говорим о наследовании мы говорим о расширении нашего приложения, тогда мы, как дизайнеры, должны выбрать, что мы должны защищать от модификации (используя частные модификаторы в нашем классе), таким образом инкапсулируя наш класс и что является открытой стороной нашего класса, которая зарезервирована для будущего расширения. (например, в языках .net это частичное представление о том, что каждый класс может быть разделен на разные файлы, поэтому некоторые из них могут быть расширены программистом, а другие - с использованием инструментов генерации кода)

...