Подтвердить что ты не робот

Принцип подписи Лискова - нет переопределяющих/виртуальных методов?

Мое понимание принципа подстановки Лискова заключается в том, что какое-либо свойство базового класса, которое является истинным или некоторым реализованным поведением базового класса, должно быть истинным и для производного класса.

Я предполагаю, что это будет означать, что когда метод определен в базовом классе, он никогда не должен переопределяться в производном классе, так как подстановка базового класса вместо производного класса даст разные результаты. Думаю, это также означало бы, что иметь (нечистые) виртуальные методы - это плохо?

Я думаю, что я мог бы неправильно понять принцип. Если я этого не сделаю, я не понимаю, почему этот принцип является хорошей практикой. Может кто-то объяснить это мне? Благодаря

4b9b3361

Ответ 1

Подклассные методы переопределения в базовом классе полностью разрешены Принципом замещения Лискова.

Это может быть слишком упрощено, но я помню, что это как "подкласс не должен требовать ничего больше и обещать не что иное"

Если клиент использует суперкласс ABC с методом something(int i), то клиент должен иметь возможность подставить любой подкласс ABC без проблем. Вместо того, чтобы думать об этом с точки зрения переменных типов, подумайте об этом с точки зрения предпосылок и постусловий.

Если наш метод something() в базовом классе ABC выше имеет смягченное предварительное условие, которое допускает любое целое число, то все подклассы ABC должны также допускать любое целое число. Подклассу GreenABC не разрешено добавлять дополнительное условие к методу something(), для которого параметр должен быть положительным целым числом. Это нарушит Принцип замещения Лискова (т.е. Требует большего). Таким образом, если клиент использует подкласс BlueABC и передает отрицательные целые числа в something(), клиент не будет разбиваться, если нам нужно переключиться на GreenABC.

В обратном случае, если базовый метод ABC class something() имеет постусловие - например, гарантируя, что он никогда не вернет нулевое значение, тогда все подклассы должны также подчиняться тому же постусловию или нарушать Принцип замещения Лискова ( т.е. обещают меньше).

Надеюсь, это поможет.

Ответ 2

Нет, это говорит о том, что вы должны иметь возможность использовать производный класс так же, как и его базу. Существует много способов переопределить метод, не нарушая этого. Простой пример: GetHashCode() в С# находится в базе для ВСЕХ классов, и все же ВСЕ их можно использовать как "объект" для вычисления хэш-кода. Классический пример нарушения правила, насколько я помню, является производным квадратом от Rectangle, поскольку Square не может иметь ширину и высоту, потому что установка одна изменит другую и, следовательно, больше не будет соответствовать правилам прямоугольника. Тем не менее, вы можете иметь базовую форму с .GetSize(), поскольку все формы могут это сделать - и, следовательно, любая производная форма может быть заменена и использована как форма.

Ответ 3

Есть один популярный пример, в котором говорится, что если он плавает, как утка, шарлатан любит утку, но требует батарей, тогда она ломает принцип замены Лискова.

Положите это просто, у вас есть базовый класс Duck, который используется кем-то. Затем вы добавляете иерархию по введению PlasticDuck с такими же переопределенными поведением (например, плавание, шарлатинг и т.д.), Как у Duck, но для их моделирования требуются батареи. Это по существу означает, что вы вводите дополнительное предварительное условие поведения Sub Class, чтобы батареи требовали того же поведения, которое ранее выполнялось классом Base Duck без батарей. Это может удивить покупателя вашего класса Duck и может нарушить функциональность, основанную на ожидаемом поведении класса Base Duck.

Вот хорошая ссылка - http://lassala.net/2010/11/04/a-good-example-of-liskov-substitution-principle/

Ответ 4

Переопределение разрывов Лисков Замена Принцип, если вы меняете любое поведение, определенное базовым методом. Это означает, что:

  • Самое слабое условие для детский метод не должен быть сильнее чем для базового метода.
  • Постусловие для дочернего метода подразумевает постусловие для родительский метод. Где постусловие формируется путем: а) всей стороны эффекты, вызванные выполнением метода, и b) тип и значение возвращаемого выражения.

Из этих двух требований вы можете подразумевать, что любая новая функциональность в дочернем методе, которая не влияет на то, что ожидается от супер-метода, не нарушает принцип. Эти условия позволяют использовать экземпляр подкласса, где требуется экземпляр суперкласса.

Если эти правила не выполняются, класс нарушает LSP. Классическим примером является следующая иерархия: class Point(x,y), class ColoredPoint(x,y,color), которая расширяет Point(x,y) и переопределенный метод equals(obj) в ColoredPoint, который отражает равенство по цвету. Теперь, если у вас есть экземпляр Set<Point>, он может предположить, что в этом наборе равны две точки с одинаковыми координатами. Это не относится к переопределенному методу equals и, как правило, просто невозможно расширить экземпляр класса и добавить аспект, используемый в методе equals без нарушения LSP.

Таким образом, каждый раз, когда вы нарушаете этот принцип, вы неявно вводите потенциальную ошибку, которая показывает, что инвариант для родительского класса, ожидаемый кодом, не выполняется. Однако в реальном мире часто нет очевидного дизайнерского решения, которое не нарушает LSP, поэтому можно использовать, например, аннотацию @ViolatesLSP класса, чтобы предупредить клиента о том, что небезопасно использовать экземпляры класса в полиморфном наборе или в любые другие случаи, основанные на принципе подписи Лискова.

Ответ 5

Я думаю, что вы в буквальном смысле верны в том, как описываете принцип и только переопределяете чисто виртуальные, или абстрактные методы гарантируют, что вы не нарушите его.

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

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

Ответ 6

краткое объяснение (щелкните по этой ссылке → ) Принцип подстановки Лискова заключается в том, что если у вас есть базовый класс BASE и подклассы SUB1 и SUB2, остальная часть вашего кода должна всегда ссылаться на BASE и NOT SUB1 и SUB2.
что это просто, просто не ссылайтесь на подклассы