LINUX.ORG.RU
Ответ на: комментарий от tailgunner

А тебе не кажется, что если пойти другим путем (Rectangle extends Square), то сломается код, завязанный на равенство сторон квадрата?

мать-перемать, и этот человек ещё что-то тут говорит :) дайте 2

shty ★★★★★
()

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

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

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

В итоге для квадрата у нас или должен нарушаться инвариант, или пропорциональное изменение другой стороны (нарушение логики вызова)

Да пример высосанный из пальца, но для простых объектов и он покатит.

далее. Пример поинтереснее: List<T extends Rectangle> Utils.get4parts(T area){ функция, которая возвращает 4 подобласти области по какому-либо правилу.

квадратную область мы можем разбить на 4 подобласти состоящих как из прямоугольников, так и 4 квадрата. Прямоугольную область мы не можем разбить на 4 квадратные обслати. При использовании функции с T=Square фунция тихо охренеет и сломается. Возражения?

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

> квадратную область мы можем разбить на 4 подобласти состоящих как из прямоугольников, так и 4 квадрата. Прямоугольную область мы не можем разбить на 4 квадратные обслати. При использовании функции с T=Square фунция тихо охренеет и сломается. Возражения?

Только одно: если я создам прямоугольник с равными сторонами, get4parts сломается?

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

Пример поинтереснее: List<T extends Rectangle> Utils.get4parts(T area){ функция, которая возвращает 4 подобласти области по какому-либо правилу.

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

Допустим, и что?

Прямоугольную область мы не можем разбить на 4 квадратные обслати.

Я тоже могу дать утверждение, что Прямоугольную область мы не можем разбить на 4 прямоугольника. И что это доказывает?

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

При использовании функции с T=Square фунция тихо охренеет и сломается. Возражения?

Не охреневает. Математика может и охреневает, а функция нет.

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

Вау. Нуу, если под сеттером понимать метод, который меняет внутренние пременные класса

inline Point get_Position( void ) const { return mPos; }
void put_Position( const Point& pt )
{
   if( ... )
   {
     ....
     mPos = ...;
   }
}

а это геттер + сеттер? просто в реальной жизни и в реальных библиотеках( а не как в советах доморощенных гуру, вроде изена ) так и пишут

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

>Их _можно_ не связывать отношениями наследования. Но можно и связать, это нормально - усиление инварианта в производных классах вполне согласуется с принципом Лисков.
Да, усиление инварианта не противоречит принципу Лисков. Но тогда код, использующий объект rectangle не должен быть уверен, что изменение ширины не изменяет высоту, так? А как это правильно описать в контракте?

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

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

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

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

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

нет, не правильно man -O2 man inline

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

>> Только одно: если я создам прямоугольник с равными сторонами, get4parts сломается?

Нет, конечно.

Тогда объясни, почему она тихо «охренеет и сломается» на квадрате.

принципа Лисков, о котором ты радостно твердишь.

Ты видишь радость у меня на лице? Да ты телепат.

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

блин

//Rectangle (int x0,int y0,int x1, int y1);
class TupoiKlass<T extends Rectangle> {
  T get4parts(Rectangle rect){
    List l = new ArrayList(4);
    l.add(new T(0,0,rect.getWidth()/4,rect.getHeight()/4);
    l.add(new T(rect.getWidth()/4,0,rect.getWidth(),rect.getHeight()/4);
    l.add(new T(0,rect.getHeight()/4,rect.getWidth(),rect.getHeight());
    l.add(new T(rect.getWidth()/4,rect.getHeight()/4,rect.getWidth(),rect.getHeight());
    return l;
  }
}

TupoiKlass<Rectangle> будет работать, а TupoiKlass<Square> нет, ясно? а должен работать.

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

А то про запирание операций с очередью понятно, но причем тут операции с объектом - уже нет. Что ты называешь per-instance mutex - тоже становится непонятно.

class Message { 
   public MsgState State { set { synchronized(this) { astate = value; } } get { synchronized(this) { return astate; } } 
   public int Retries { set { synchronized(this) { retries = value; } } get { synchronized(this) { return returies; } } 
    public synchronized void proceed() {
         if (State==MsgState.RUNNING) { return; // Умереть или выйти; }
         State = MsgState.RUNNING;
         .... 
         State = MsgState.COMPLETE; 
    } 
} 
 
class Queue { 
    Message findMsg() { 
        synchronizde(this) { 
            foreach(messages) { if (messages[index].State==MsgState.WAIT) { 
                iret = messages[index]; 
                moveToTheEnd(messages[index]); 
                return iret; 
            } 
        } 
    } 
} 
 
class Processor extends Thread { 
    public void Run() { 
        while ((msg=queue.findMsg())!=null) { msg.proceed(); } 
    } 
} 
 
class Cleaner extends Thread { 
    public void Run() { 
        while (!aborted) { 
           msg=queue.pollCompletedMsg(); 
           msg.flushState(); 
           msg.Destroy; 
        } 
    } 
} 

И даже то, что здесь не объявлено ни одного мутекса не означает, что их нет (ибо synchronized). То есть будешь ты явно их ставить, или писать synchronized на методе/свойстве/декларации класса, уже мало кого волнует.

no-dashi ★★★★★
()
Ответ на: комментарий от lester

а это геттер + сеттер?

Угу. Именно они, родимые, и есть.

no-dashi ★★★★★
()
Ответ на: комментарий от tailgunner

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

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

> Я тоже могу дать утверждение, что Прямоугольную область мы не можем разбить на 4 прямоугольника. И что это доказывает?

Это доказывает то, что ты можешь давать неверные утверждения //К.О.

qnikst ★★★★★
()
Ответ на: комментарий от no-dashi

> И даже то, что здесь не объявлено ни одного мутекса не означает, что их нет (ибо synchronized)

Я знаю. У меня только 1 вопрос: извлекается ли Message из Queue перед тем, как пойти на обработку? Вроде бы нет, но я хочу услышать четкий ответ от тебя, потому что именно из-за того, что оно остается в очереди, тебе пришлось сделать Message синхронизированным по самую плешь.

Сообщение должно передвигаться _между_ очередями, извлекаться из одной, проходить обработку в Processor, заноситься в другую, проходить обработку в Cleaner, и исчезать. ИМХО, ты усложнил простую и понятную схему без всякого профита.

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

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

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

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

функция работающая над объектом типа rectangle и возвращающая объекты типа rectangle всегда может разбить область на 4 прямоугольника, _всегда_. Пример работающего _всегда_ разбиения я привёл :)

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

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

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

Это не проблема подставновки, а проблема математических вычислений.

Мой пример:

Square quad = new Square(System.out);
quad.resize(50);
quad.resize(40, 40);
Rectangle rq = (Rectangle)quad;
rq.move(167, 54);
rq.resize(20);
rq.resize(23, 89);
Работает:
ClassName: class clientpackage.Square
Размеры: x=0 y=0 width=50 height=50
ClassName: class clientpackage.Square
Размеры: x=0 y=0 width=40 height=40
ClassName: class clientpackage.Square
Размеры: x=167 y=54 width=40 height=40
ClassName: class clientpackage.Square
Размеры: x=167 y=54 width=20 height=20
Exception in thread "main" java.lang.UnsupportedOperationException: Квадрат не может имееть разные стороны.
	at clientpackage.Square.resize(Square.java:15)
	at clientpackage.FigureTest.main(FigureTest.java:28)
— принцип подстановки сохраняется, как ни странно. Квадрат просто усиливает инвариант равенства сторон при изменении размера.

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

> В случае если мы наследуем square от rectangle, то функция, которая должна возвращать объекта типа 4 square и должна вернуть результат и тут (ведь это работает на уровне предыдущем уровне абстракции), работать не будет.

По-моему, ты упорно уходишь от ответа. Жаль, у меня нет времени прогнать твой код через компилятор. Ты сам его пробовал? Если да, то покажи, как он сбоит.

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

Ладно, пример с фигурами может и не удачный, но по поводу следующего утверждения

Но можно и связать, это нормально - усиление инварианта в производных классах вполне согласуется с принципом Лисков.

возникают огромные сомения.

Т.к. ] существует класс A с инвариантами invA_1(A),invA_2(A),... и класс наследник B, такой, что invB_1(B),invB_2(B).

так же пусть есть функция xi xi(A)->A, такая, что \forall a\in A xi(a)=a', выполяется все инварианты вида invA_i.

Согласно принципу Лисков, мы можем заменить A на класс наследник B. получаем, что xi(B)->B. invA_i(b') выполняются, однако у нас нету никакой гарантии выполнения invB_i(b'). в итоге мы получаем, что на самом деле при замене A->B мы можем гарантировать только xi(B)->A, но не xi(B)->B. приходим к тому, что у нас не должно быть доп инвариантов отвечающих классу B.

коряво но всё же

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

> Utils.расширитьВ2раза(Rectangle rect); будет работать с прямоугольником, но не будет с квадратом => нарушение принципа Лисков.

я по-другому понимаю ЛСП и думаю, что ООП-шная форма записи искажает его суть.

Rectangle расширитьВ2раза(Rectangle r) { return new Rectangle(r.x, r.y*2) }

Rectangle расширитьВ2раза(Square r) { return new Rectangle(r.x, r.y*2) }

вполне себе LSP — никто не засталяет иметь «T расширитьВ2раза(T) where T extends Rectangle»

вполне достаточно «Rectangle расширитьВ2раза(T) where T extends Rectangle»

и только тупая запись T.расширитьВ2раза() where T extends Rectangle приводит к проблеме

так же и в твоем другом примере с разбиением — ты требуешь ко- или контра- вариантность там, где она не обязательна З.Ы. проблема тут все же есть, кто ее знает?

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

> Ладно, пример с фигурами может и не удачный, но по поводу следующего утверждения

Но можно и связать, это нормально - усиление инварианта в производных классах вполне согласуется с принципом Лисков.

возникают огромные сомения.

Подозреваю, что здесь дело в том. какой именно контракт (специально не пишу «инвариант») использует код. Какой-то контракт квадрат моджет нарушать.

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

в общем походу близимся к общей точке зрения.

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

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

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

> — принцип подстановки сохраняется, как ни странно. Квадрат просто усиливает инвариант равенства сторон при изменении размера.

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

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

чуть изменим пример. У нас есть платёжный документ Invoice, и библиотека, которая работает с данными инвоисами.

В фирме разработчика I ведётся работа с платёжками с суммой >0. Разработчик I реализует класс InvoicePlus наследник Ivoice, который бросает исключение IllegalStateException если сумма меньше нуля. Все тестируется на простых примерах и запускается.

Далее в систему разработанную разработчиком I приходит отмена платёжки (платёжка с отрицательной суммой, равной сумме отменяемой платёжки). Система всесто того, чтобы успешно обработать данный invoice функцией из библиотеки выдаёт IllegalStateException и работа встаёт. Разработчик отвечает, что IvoicePlus просто усиливает инвариант Invoice. Работа стоит деньги теряются, кто виноват что делать?

В общем то стандартное наследование в ООП противоречит законам логики, к которым мы привыкли, возможно это проблема терминологии, но с этим ничего не сделать =)

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

> По-моему, ты упорно уходишь от ответа. Жаль, у меня нет времени прогнать твой код через компилятор. Ты сам его пробовал? Если да, то покажи, как он сбоит.

после 19.00 MSK постараюсь предоставить код и примеры и что я вообще имею ввиду, если не придём к понимаю мнений др друга. а пока работа :)

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

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

class Rect extends Square почти бесполезно, т.к. в классе квадрата мы не можем положиться ни на один его инвариант, отсутствующий у прямоугольника, так что сразу можно брать класс прямоугольника

интересно исключение — это тот случай, когда наследник аггрегирует (для вызова вирт. функций) изоморфный, но не равный первоначальному родитель  — т.е. по русски повернутый квадрат, но это с практической точки зрения извращение :-)

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

> class Rect extends Square почти бесполезно, т.к. в классе квадрата мы не можем положиться ни на один его инвариант, отсутствующий у прямоугольника, так что сразу можно брать класс прямоугольника

согласен :) я про то, что в случае Square extends Rect всё хуже.

тут логично делать наследование по логике действий, что-то типа иерархии интерфейсов:

IFigure->IResizable->IStretchable

и соотв иерархии абстрактных классов Figure->Resizable->Stretchable,

и уже от них final классы реализующие собственно фигуры.

А потом уже можно делать всякие Draggable и т.п. для перемещения и тому подобных действий.

В общем iZEN про, что-то похожее говорить пытался (мне кажется)

//то, что для фигур есть гораздо более хорошие возможности составить иерархию ясно, но обсуждение именно в контексте

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

> Система всесто того, чтобы успешно обработать данный invoice функцией из библиотеки выдаёт IllegalStateException и работа встаёт. Разработчик отвечает, что IvoicePlus просто усиливает инвариант Invoice. Работа стоит деньги теряются, кто виноват что делать?

кидание исключений — это (как и в данном случае) способ аккуратно завершить операцию по причине того, что программа «пошла в разнос», т.е. работает не так, как замышлял программер и не может применяться для *оправдания* нарушения ЛСП, а только для рантаймовой диагностики этого (неожиданного) нарушения.

в моем примере все функции исключений не кидают

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

> я про то, что в случае Square extends Rect всё хуже.

Square extends Rect вполне пригоден (при некоторых дополнительных фичах языка программирования)

ладно, сразу скажу — например, при немутабельных объектах, но ИМХО есть еще варианты.

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

ну не должно такого быть, со всеми наследниками класса всё должно работать без лишних Exception.

функция декларированная как void doSmth(Rectagle rect); (без всяких искоючений) не должна выбрасывать IllegalStateException никогда.

Решение если очень хочется использовать данную функцию и для квадратов: сделать прокси, которое создаёт из Square fake прямоугольник, потом фукнкция работает с ним, потом мы возвращаем состояние назад, проверяя инварианты. Тут всё ок.

прототип: [code] class Proxy { static Rectangle sToR(Square s) { Rectangle r = new Rectangle(); //определение свойств return r; } static Square rToS(Rectangle r) throw IllegalStateException { Square s = new Square(); //определение свойств return s; } } //usage: Square s; Rectangle r = Proxy.sToR(s); Utils.doSmth(r); try { s=Proxy.rToS(r); } catch(Exception e) { //ловим и делаем, что хотим } [/code]

P.S. Знаю Реализация прокси говно, а не реализация.

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

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

ошибка, которая приводит к нарушению LSP и к проблемам совместимости в данном случае - использование статических аннотаций (тип обьекта) для описания динамических ограничений. какой бы ни была предложенная заглушка (значение по умолчанию, нет функционала, дублирование функционала, etc) всегда можно будет придумать поведенческий инвариант, который подобным образом будет нарушен; отсюда следуют трудноуловимые баги в клиентском относительно данного коде. вывод, вообще говоря, очевиден - костыль он и есть костыль, полагаться на него нельзя; жаль, что местные гуру до этого понимания ещё не дошли

что же касается решения для приведённого мной примера, то их есть по-крайней мере два: либо использовать язык с динамическими аннотациями типов (прямоугольник с двумя равными сторонами принимает тип квадрат); либо не использовать статических аннотаций вообще (не наследовать квадрат от прямоугольника, т.к. отношение «является в смысле LSP» не выполнено). в любом случае выдавать одну сущность за другую смысла нет

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

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

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

при немутабельных объектах

да, в случае иммутабельности проблема тоже отпадает, но это уже более сильное ограничение на вызываемый код (аналог Edison API для C++ вроде пока никто не написал)

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

либо не использовать статических аннотаций вообще (не наследовать квадрат от прямоугольника, т.к. отношение «является в смысле LSP» не выполнено). в любом случае выдавать одну сущность за другую смысла нет


имхо, 2/3 противников тебе тоже самое и говорят ^_^

#ifdef возвращение_к_старой_теме
казалось бы а *еттеры тут при чём
#endif

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

казалось бы а *еттеры тут при чём

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

имхо, 2/3 противников тебе тоже самое и говорят ^_^

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

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

> при их использовании возникает та же проблема, что и при нарушении LSP наследованием: если геттеры/сеттеры выведены в интерфейс, а реализация в силу каких-либо причин была изменена, получаем тот же эффект, что и при наследовании квадрата от прямоугольника: интерфейс остался прежний, но отношения «является в смысле LSP», т.е. поведенческой совместимости, добиться невозможно. как результат - рефакторинг и изменение интерфейса

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

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

Не сложно будет написать пример, где это возникает?

так я же его уже выше и писал: вот. был класс Rect, мы изменили его реализацию (два поля превратились в одно). что делать с интерфейсом, который по-прежнему содержит геттеры/сеттеры на оба поля? отношение «является» у нас возникает не вследствие наследования, а вследствие рефакторинга: тип остался тот же, изменилась только его реализация. можем ли мы оставить интерфейс неизменным (инкапсуляция именно это нам гарантирует)? нет, не можем

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

Мне кажется, что тут ответ достоин К.О.. Класс Rect не должен меняться таким образом, чтобы нам было необходимо менять интерфейс поскольку мы теряем корректность работы на уровне абстракции. У нас есть интерфейс, но новый класс (изменённый старый) не соответствует.

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

Теперь по поводу *еттеров.

class A
{
  public: double nonNull(int a){ return nonNil;}
}

class B
{
  public: double nonNull(double b){ return 0;}
}

double func(A const & a) 
{ 
    return 1/a; 
} 
 
double func(B const & b) 
{ 
    return 1/b; 
} 



Здесь тоже будут проблемы, но геттеров и сеттеров нет. Изменилась реализация, которая теперь не соответствует заявленному, *еттеры ни при чём j.J, или я что-то в твоих словах не понимаю
qnikst ★★★★★
()
Ответ на: комментарий от qnikst

лень код править, да и не стоит оно того :)

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

> был класс Rect, мы изменили его реализацию (два поля превратились в одно). что делать с интерфейсом, который по-прежнему содержит геттеры/сеттеры на оба поля?

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

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

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

что-то ты подзабыл о чём говорилось -> иди перечитай :)

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

так я же его уже выше и писал: вот. был класс Rect, мы изменили его реализацию (два поля превратились в одно). что делать с интерфейсом, который по-прежнему содержит геттеры/сеттеры на оба поля?

вот опять сказка про белого бычка :)

Вам уже намекнули что задача в такой постановке некорректна, и это ещё мягко говоря

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

Здесь тоже будут проблемы, но геттеров и сеттеров нет

а что - из того факта, что класс можно неправильно спроектировать и без геттеров/сеттеров следует что они не порождают проблем? это определённо новое слово в логике :)

Класс Rect не должен меняться таким образом, чтобы нам было необходимо менять интерфейс

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

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

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

такое ощущение, что переписывание и переделывание - основная задача проектировщиков

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

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

> но если на исходные поля у нас будут выведены геттеры/сеттеры, любое подобное изменение будет требовать рефакторинга

ты так говоришь будто это что-то плохое :), вон Фаулер целую книжку написал, где объяснил, что рефакторинг дело нужное и бояться его не надо, а удаление поля из объекта при грамотном проектировании происходит крайне редко, точно так же я могу сказать - а вдруг ты в методе Move уберешь второй параметр, что тогда? рефакторинг? ужас какой!

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

вот здесь ты утверждаешь, что можешь добиться совместимости:

shty

если приспичило зачем то обуспечить совместимость - делаем так

приведённый код, естественно, не работает. в качестве отмазки ты выдаёшь вот это:

shty

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

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

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

вон Фаулер целую книжку написал, где объяснил, что рефакторинг дело нужное и бояться его не надо

и он же, тем не менее, утверждает что геттеры/сеттеры - зло, и их следует по возможности избегать ;) рефакторинг можно любить, но только, гм, to some extent

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