LINUX.ORG.RU

Что дает принцип Лисков?

 


0

1

Лисков утверждает [сами знаете что]. Хочется спросить. А зачем это вообще? Допустим, «клиентский» код не может рассчитывать на эти контракты, и для типа и подтипа нужно делать разных клиентов. Ну и что с того? Как это осложняет проектирование? Какая нафиг, вообще разница?

Ответ на: комментарий от callbackhell

Иметь ввиду?

Вот смотри - ты отнаследовал (для реализации) квадрат от прямоугольника. Клиент должен иметь ввиду,что обрабатывать их нужно по разному. И как собственно говоря теперь объяснить это клиенту?

В Java и C# например, если ты отнаследовал квадрат от прямоугольника, все - клиенты смогут обрабатывать их одинаково. Как теперь клиенту узнать, что ему нельзя обрабатывать их одинаково?

anonymous
()
Ответ на: комментарий от callbackhell

Вот мы пишем код. В коде много неявных предположений. В частности, если мы используем Java или C#, одно из основных неявных предположений - «если имеет место наследование, значит это наследование поведения». Собственно, это логично в языке, поддерживающем только наследование поведения.

А тут раз, и получите - оказывается, хоть и имело место наследование, но это не было наследование поведения. И хотя наследник включает все поведение предка, пользоваться поведением предка нельзя.

Окей. На это мы в принципе можем и забить - будем помнить как частный случай. Но таких мест, таких частных случаев со временем станет столько, что потом только и будешь что копаться в них. Кому это надо?

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

anonymous
()
Ответ на: комментарий от anonymous

Вот смотри - ты отнаследовал (для реализации) квадрат от прямоугольника. Клиент должен иметь ввиду,что обрабатывать их нужно по разному. И как собственно говоря теперь объяснить это клиенту?


Rectangle := Object clone do(
   width ::= 0
   height ::= 0
   square := method(width * height)
)

Square := Rectangle clone do(
   width = nil
   height = nil
   size ::= 0
   square := method(size * size)
)

Client := Object clone do(
   calculateSumOfSquares := method(figure,
        figure square + figure square
     )
   )
   change := method(figure, 
      if(
        figure type == "Rectangle",
        figure do( setWidth(width + 1); setHeight(height + 1))
      )
      if(
        figure type == "Square",
        figure do( setSize(size + 1) )
      )
)


rectangle := Rectangle clone setWidth(10) setHeight(20)
square := Square clone setSize(15)
client := Client clone

Client calculateSumOfSquares(rectangle) println
Client calculateSumOfSquares(square) println
Client change(square)
Client change(rectangle)

square size println
rectangle width println
rectangle height println

#>>>> 400
#>>>> 450
#>>>> 16
#>>>> 11
#>>>> 21

callbackhell
() автор топика
Ответ на: комментарий от anonymous

А тут раз, и получите - оказывается, хоть и имело место наследование, но это не было наследование поведения

Почему не наследование поведения? Просто часть поведения наследуется, а часть нет. Папа может ходить и трахаться, а сын ходит может, а трахаться еще не положено, но умение ходить отнаследовать никто не запрещает. Я вообще не врубаюсь что там за проблемы в жабе, это абзац какой-то.

callbackhell
() автор топика
Ответ на: комментарий от anonymous

будем помнить как частный случай

Какая разница, врубаешься ли ты в подкласс как частный случай, или в отдельный класс? Подкласс все равно дает больше гибкости и экономии.

callbackhell
() автор топика

Не знаю как там насчёт прин ципа, а так вообще Николай Семёнович отличный писатель.

anonymous
()
Ответ на: комментарий от callbackhell

Хорошо. Есть ли разница между этим...

public interace ChangeablePlainFigure {
    public double square();
    public void change();
}

public class Square implements ChangeablePlainFigure {
    private double size;
    public Square(double size) { this.size = size; }
    public void change() { this.size++; }
    @Override
    public double square() { return this.size * this.size; }
    public double getSize() { return this.size; }
}

public class Rectangle implements ChangeablePlainFigure {
    private double width, height;
    public Rectangle(double width, double height) { this.width = width; this.height = height; }
    public void change() { this.width++; this.height++; }
    @Override
    public double square() { return this.width * this.height; }
    public double getWidth() { return this.width; }
    public double getHeight() { return this.height; }
}

И этим...

public class Rectangle {
    private double width, height;
    public Rectangle(double width, double height) { this.width = width; this.height = height; }
    public void change() { this.width++; this.height++; }
    public double square() { return this.width * this.height; }
    public double getWidth() { return this.width; }
    public double getHeight() { return this.height; }
}

public class Square extends Rectangle {
    private double size;
    public Square(double size) { this.size = size; }
    @Override
    public double square() { return this.size * this.size; }
    @Override
    public double getWith() throws NotImplementedException { throw NotImplementedException; }
    public double getHeight() throws NotImplementedException { throw NotImplementedException; }
    public double getSize() { return this.size; }
    @Override
    public void change() { this.size++; }
}

И вопрос остается открытым - как объяснить клиенту во втором случае, что вызывать getWith() и getHeight() нельзя?

anonymous
()
Ответ на: комментарий от anonymous

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

как объяснить клиенту во втором случае, что вызывать getWith() и getHeight() нельзя?

Что значит объяснить? Он будет реализован так, что он не будет этого делать. Можно сделать как у тебя, дополнительно генерировать ошибку при попытке обращения

callbackhell
() автор топика
Ответ на: комментарий от anonymous

ак объяснить клиенту во втором случае, что вызывать getWith() и getHeight() нельзя

В моем случае он проверяет тип объекта, и в соответствии с этим обрабатывает

callbackhell
() автор топика

А зачем это вообще?

Критерий оценки кода.

Допустим, «клиентский» код не может рассчитывать на эти контракты, и для типа и подтипа нужно делать разных клиентов.

следовательно код говно.

Ну и что с того?

в 90% случаев к сожалению ничего.

Как это осложняет проектирование?

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

Какая нафиг, вообще разница?

Для тебя думаю никакой.

TDrive ★★★★★
()
Ответ на: комментарий от TDrive

усложняется поддержка

Она усложняется именно потому, что хомячки думают что принцип Лисков __нужен__. Алан Кей ни о каких Лисков понятия не имеет.

callbackhell
() автор топика
Ответ на: комментарий от TDrive

ошибка проектирования

Ошибка проектирования с точки зрения кухарки, которая возомнила себя *ученым-компуторсайентогогом*, как это трогательно.

callbackhell
() автор топика
Ответ на: комментарий от callbackhell

Что значит нужен, кому нужен?) Это инструмент (критерий) помогающий найти ошибку проектирования. Он не может быть нужен или не нужен, он просто есть и им можно пользоваться)

TDrive ★★★★★
()
Ответ на: комментарий от callbackhell

Ошибка проектирования с точки зрения кухарки, которая возомнила себя *ученым-компуторсайентогогом*, как это трогательно.

как скажешь)

TDrive ★★★★★
()
Ответ на: комментарий от TDrive

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

callbackhell
() автор топика
Ответ на: комментарий от TDrive

Данный принцип является, по большому счету вообще абсурдным. Я уже приводил пример с отцом и сыном. Мы не можем допустить, чтобы малолетка трахался, но все остальное можно унаследовать от отца. Это нарушает принцип Лисков.

callbackhell
() автор топика
Ответ на: комментарий от callbackhell

Вот есть у тебя например класс Animal, у этого класса есть свойства например цвет и вес + метод move или say пофигу. А потом тебе вдруг понадобилось сделать класс Кирпич, у которого так же есть цвет и вес, и ты такой типо, «О! Я же могу реюзнуть этот код из анимал! DRY наше все». И ты наследуешь класс кирпич от класса animal, а на методы say и move просто забиваешь, и ты на 100% уверен что ни кто не додумается юзать на объектах класса кирпич метод say и код у тебя весь отDRYен и отлично работает, и тесты все проходят... Но любой адекватный человек скажет что тут ошибка проектирование и как раз тут не выполняется принцип Лесков. Совпадение? Не думаю!

TDrive ★★★★★
()
Ответ на: комментарий от callbackhell

Покажи мне, где об этом говорит Алан Кей, или какой-то другой дизайнер Ъ-языка.

По твоему информатика ни как не развивается?

TDrive ★★★★★
()
Ответ на: комментарий от callbackhell

Мы не можем допустить, чтобы малолетка трахался, но все остальное можно унаследовать от отца. Это нарушает принцип Лисков.

Не правильно, фактически он может трахаться, если мы не можем этого допустить, во первых кто мы? отдельный какой то объект, например Закон, нам нужно ввести какие то критерии определения может он трахаться или нет в зависимости от своего состояния, например возраст. Причем логика проверки этих критериев будет находиться в объекте Закон, более того Закон может быть разный (в разных странах) с разной логикой проверки критериев.

Видишь какие у тебя фатальные ошибки?

TDrive ★★★★★
()
Ответ на: комментарий от TDrive

Не надо передергивать. И для твоего случая дебильного даже, гипотетически можно придумать абстракцию, materialObject, а от него выстроить иерерхию до Animal, но вряд ли это кому то понадобится в реальном проектировании.

callbackhell
() автор топика
Ответ на: комментарий от callbackhell

вот как раз сделать объект materialObject и выстроить от него иерархию до Animal и Кирпич будет рефакторингом ранее написанного говнокода)

TDrive ★★★★★
()
Ответ на: комментарий от TDrive

Не правильно, фактически он может трахаться, если мы не можем этого допустить, во первых кто мы? отдельный какой то объект, например Закон, нам нужно ввести какие то критерии определения может он трахаться или нет в зависимости от своего состояния, например возраст. Причем логика проверки этих критериев будет находиться в объекте Закон, более того Закон может быть разный (в разных странах) с разной логикой проверки критериев.

Куда-то тебя понесло не в ту степь. Достаточно затереть у него метод fuck.

callbackhell
() автор топика
Ответ на: комментарий от callbackhell

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

TDrive ★★★★★
()
Ответ на: комментарий от callbackhell

Развивается, в обратную сторону. Деградирует.

Если ты действительно в этом уверен то я не вижу смысла, что либо тебе доказывать, с моей стороны это будет бесполезной тратой времени)

TDrive ★★★★★
()
Ответ на: комментарий от TDrive

а когда тебе нужно будет ввести понятие разных стран в половине которых он может трахаться?

Тут самое правильное решение это реализация метода в зависимоcти от гражданства


fuck := method(
  if(national == russian, ...)
  if(national == indian, ...)
)

callbackhell
() автор топика
Ответ на: комментарий от callbackhell

Гражданство тут вообще не причем, важно то в какой стране он находится в данный момент. Собственно, очередные ошибки проектирования...

TDrive ★★★★★
()
Ответ на: комментарий от TDrive

Чего? Во первых, это юридическая ошибка. А во-вторых, я что то сомневаюсь, что резидент какой-либо страны не подпадает под юрисдикцию своей страны, находясь за рубежом. Например, ты так мог бы безнаказанно продать свою родину, выдав какую-нибудь гостайну, находясь в какой-нибудь прибалтике или, хуже того, в Казахстане.

callbackhell
() автор топика
Ответ на: комментарий от callbackhell

Чего? Во первых, это юридическая ошибка

Чего?)

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

А это уже зависит от системы которую ты проектируешь, так сказать от твоей виртуальной реальности, как видишь тебе уже потребовалось ввести понятия страны, юрисдикции, критерией подпадания под эту юрисдикцию, понятие зарубежа и тд. моя схема с законом отлично расширяется под все это а ты видимо все это будешь пихать в метод fuck?) А если добавить методы drinkAlcohol, driveCar, и еще штук 100 подобных у каждого из которых свои критерии применимости?)

TDrive ★★★★★
()
Ответ на: комментарий от TDrive

Зависит от конкретного кейза. Я не говорю что схема с законом плоха, но она может оказаться избыточной, например. Безотносительно конкретной задачи говорить об этом бесполезно.

а ты видимо все это будешь пихать в метод fuck

Метод fuck тоже может обратиться к Закону, одно другое не исключает.

callbackhell
() автор топика
Ответ на: комментарий от callbackhell

Не говоря уже о том что тебе наверняка понадобится как то проверить может он делать fuck или не может без вызова этого метода...

TDrive ★★★★★
()
Ответ на: комментарий от callbackhell

Зависит от конкретного кейза.

В конкретном кейзе кирпич прекрасно наследуется от энимал.

Метод fuck тоже может обратиться к Закону, одно другое не исключает.

Конечно может, как напишешь так и будет, тут все от тебя зависит) Только это будет говнокод.

TDrive ★★★★★
()
Ответ на: комментарий от TDrive

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

callbackhell
() автор топика
Ответ на: комментарий от callbackhell

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

TDrive ★★★★★
()
Ответ на: комментарий от TDrive

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

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

callbackhell
() автор топика
Ответ на: комментарий от callbackhell

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

Ну да если яп говно то его использовать не стоит) А так, все стандартные шаблоны проектирования нормально воспроизводятся на всех популярных яп.

Во-вторых, расширение системы тоже зависит от языка очень сильно, и это надо учитывать при проектировании.

Нет, расширение системы зависит от того что вчера пил и с какой ноги встал менеджер который ставит программистам задачи.

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

Если у тебя 50к строк говнокода ты его на любом ЯП малыми жертвами не перепишешь. А если у тебя под этот говнокод еще и 50 гигов данных в базе которые надо как то мигрировать на новую схему...

TDrive ★★★★★
()
Ответ на: комментарий от TDrive

воспроизводятся на всех популярных яп.

Все популярные языки — говно. А шаблоны проектирования на них сильно отличаются от тех, которые на нормальных. Естественно, они воспроизводятся на нормальных языках, легко, только в большинстве случаев они не нужны на них, так как являются отражением кривости этих недоязычков. И даже не только паттерны, но и методологии проектирования, и подход к написанию кода — все абсолютно другое.

callbackhell
() автор топика
Ответ на: комментарий от callbackhell

Какой конкретно шаблон проектирования является отражением кривости какого яп? Давай конкретику что бы не заниматься демагогией как ты сказал.)

TDrive ★★★★★
()
Ответ на: комментарий от TDrive

Например, паттерн «Строитель», как-то разбирал его, так и не понял, нахрен он нужен, простейшая логика, которая реализуется в три строки, размазана на кучу говнокода. Нахрен объекту нужен какой-то отдельный строитель, если у него есть конструктор?

callbackhell
() автор топика
Ответ на: комментарий от callbackhell

Нет нет стоп.) Давай так, какой шаблон проектирования который ты понял является отражением кривости какого нибудь конкретного яп. То есть тебе нужно назвать 1) шаблон 2) яп 3) почему он отражает кривость этого яп.

Если ты не вкурил какой то паттерн то какой тут вообще может быть разговор про кривость?

Лекция по смыслу конкретных паттернов не сегодня, сорян.

TDrive ★★★★★
()
Ответ на: комментарий от TDrive

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

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

callbackhell
() автор топика
Ответ на: комментарий от TDrive

с утра

Ага с утра. Учитывая, что ты лег под утро, утро у тебя начнется часов в пять вечера:)

callbackhell
() автор топика
Ответ на: комментарий от anonymous

Во втором примере смешались люди и кони, ему совсем чуть-чуть не хватает чтобы не нарушать LSP. Поэтому он такой кривой и неубедительный. Ты только путаешь нашего дурачка.

public class Square extends Rectangle {
    public Square(double size) { this.width = this.height = size; }
}
A1
()
Ответ на: комментарий от callbackhell

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

нет ты его не вкурил

В качестве пруфа я могу переписать тот же код на Io, без ущерба для логики, но в разы короче и не плодя сущности.

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

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

В той же java есть статические методы/переменные.

TDrive ★★★★★
()
Ответ на: комментарий от callbackhell

я могу переписать тот же код на Io

3.14здобол-фантаст. Дальше хеловордов ты ничего не можешь и своими вскукареками в этой теме ты еще раз это доказал.

anonymous
()
Ответ на: комментарий от callbackhell

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

anonymous
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.