![]() |
|
Модераторы: Daevaorn |
![]()
|
|
| Rockie |
|
||||
|
Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1143 Регистрация: 23.4.2006 Репутация: 8 Всего: 31 |
не понимаю предпоследний абзац. что хотел сказать автор этим правилом?
-------------------- Чтобы иметь большой гардероб - надо иметь большой гардероб. |
||||
|
|||||
| bsa |
|
|||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Модератор Сообщений: 9185 Регистрация: 6.4.2006 Где: Москва, Россия Репутация: 63 Всего: 196 |
Думаю, автор имел в виду, что если у тебя член класса x методами get и set только читается и изменятся, то эти методы не имеют смысла, так как компилятор все равно при оптимизации будет просто подставлять значение данного члена (без вызова метода).
Вот только я не уверен, что неиспользование это хорошо. По-моему, лучше get/set использовать, так как в случае если при изменении данного параметра придется еще выполнять ряд действий, то не придется менять интерфейс класса (проще говоря, не придется переписывать уже написанные программы, использующие этот класс). А читабельность можно повысить правильным форматированием. |
|||
|
||||
| Fazil6 |
|
|||
|
Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1653 Регистрация: 3.5.2006 Где: Минск Репутация: 35 Всего: 60 |
bsa,
нет совсем не это имел в виду автор. В этой книге автор несколько раз приводится пример про календарь. на самом деле имеется в виду, что данные класса в правильно спроектированном классе не представляют инттереса вне класса. Нужно рассматривать класс, как самодостаточную вещь и оперрировать не данными класса, а его интерфейсом. Подход в том, что данные закрыты не для того чтобы просто затруднить к ним доступ, а в первую очередь потому, что в правильном классе нет необходимости в доступе к данным извне класса, а есть функции типа "сделай что-то" , "создай это" и тд. а set и get на самом деле по сути нарушают инкапсуляцию |
|||
|
||||
| DeadSoul |
|
|||
|
Эксперт ![]() ![]() ![]() Профиль Группа: Участник Сообщений: 1217 Регистрация: 25.9.2005 Где: Москва Репутация: 2 Всего: 11 |
В этом автор ошибается. 1. С течением времени смысл этих методов может изменится 2. С getter-ами\setter-ами проще отлаживатся, т.е. найти то место где туда устанавливается не очень корректное значение -------------------- Если Вы получили ответ на Ваш вопрос, то нажмите на "Вопрос решен". Бьем спамеров их же оружием. Пусть весь спам сыпется им [email protected] |
|||
|
||||
| Fazil6 |
|
||||||
|
Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1653 Регистрация: 3.5.2006 Где: Минск Репутация: 35 Всего: 60 |
про читабельность там с иронией говорится. Добавлено @ 22:19
|
||||||
|
|||||||
| bsa |
|
|||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Модератор Сообщений: 9185 Регистрация: 6.4.2006 Где: Москва, Россия Репутация: 63 Всего: 196 |
Fazil6
Тебе бы книжки писать - объяснение намного понятнее. |
|||
|
||||
| sergejzr |
|
|||
![]() Un salsero Профиль Группа: Админ Сообщений: 13285 Регистрация: 10.2.2004 Где: Германия г .Ганновер Репутация: 19 Всего: 360 |
Fazil6, хорошо обьяснил.
Я тоже так понял, что автор не призывает "ни в коем случае не использовать геттеры и сеттеры". А хочет сказать, что если они в программе вдруг станут необходимы - класс спроектирован плохо. |
|||
|
||||
| Fazil6 |
|
|||
|
Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1653 Регистрация: 3.5.2006 Где: Минск Репутация: 35 Всего: 60 |
вообще-то я советую всем, кто не читал эту книжку, прочитать, хоть она и не первой свежести. Автор четко знает о чем пишет, все с прекрасными примерами из жизни и юмором. Читается очень увлекательно
|
|||
|
||||
| Rockie |
|
|||
|
Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1143 Регистрация: 23.4.2006 Репутация: 8 Всего: 31 |
Ага! Если я правильно понял, то, к примеру, вместо set использовать инициализацию в конструкторе, а заместо get использовать к примеру методы "Распечататься", "Записаться в файл" и др. Таким образом, необходимость в методах set и get должна отпасть сама собой. bsa, Fazil6, DeadSoul, sergej.z, всем участникам большое спасибо! -------------------- Чтобы иметь большой гардероб - надо иметь большой гардероб. |
|||
|
||||
| En_t_end |
|
|||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 2074 Регистрация: 4.12.2004 Репутация: 1 Всего: 20 |
А почему нельзя get'ы использовать ?(c set'ами все понятно...)
Добавлено @ 11:45 допустим, мне нужно собрать статистику со всех классов. В каждом классе есть метод GetOccupied. Неужели этот метод нарушает инкапсуляцию ? То есть технологию аксессоров нельзя применять ? |
|||
|
||||
| ivashkanet |
|
|||
![]() Кодю потиху ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 3684 Регистрация: 23.2.2006 Где: Гомель, Беларусь Репутация: нет Всего: 149 |
А как передавать настройки новому классу? Через методы, или может в конструкторе?
То же, ИМХО, ерунда. Невозможно учесть все возможные стороны применения нашего класса. Что если через год нам понадобиться метод которого нет? Переписывать класс? P.S. Стандартные классы направо и налево используют открытые свойства. Врятли программисты не знали свое дело, когда проектировали их. Даже больше -- они же и создавали стандарты языка Представьте что бы было если бы "самый главный" класс Form не имел открытых свойств. Что бы тогда было. Заголовок, положение, размеры, ... все передавать через конструктор? + Обясните мне разницу между методом Form.SetCaption("Название формы") и Form.Caption = "Название формы" с точки зрения работы программы? ... Да ее просто НЕТ P.P.S. Я сам .Net-чик, поэтому не знаю как в С++ называется свойство заголовка формы Добавлено @ 13:51 Продолжу Несомненным плюсом Сеттеров является то, что мы можем провести валидацию данных и в случае несоответствия выкинуть исключение. Именно поэтому не стоит использовать открытые поля классов. Они не поддерживают валидацию. У Геттеров такого явного преимущества нет Перечитайте этот отрывок. Все ли понятно после первого прочтения? |
|||
|
||||
| Daevaorn |
|
||||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 2155 Регистрация: 29.11.2004 Где: Москва Репутация: 51 Всего: 70 |
Хорошая шутка
Можно пример? Ещё привлекает внимаение слово "свойства"...
Да. Если такое произошло - значит существет ошибка в проекитировании этого самого класса. |
||||
|
|||||
| Fazil6 |
|
||||
|
Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1653 Регистрация: 3.5.2006 Где: Минск Репутация: 35 Всего: 60 |
именно через методы или в конструкторе.
Не думай, что гуишные классы NET, VCL или MFC являются стандартом программирования и речь идет о ООП в теории, а не конкретной реализации конкретных классов. Свойство - это интерфейс класса, а не данные класса и именно об этом говорит автор. |
||||
|
|||||
| ivashkanet |
|
||||||
![]() Кодю потиху ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 3684 Регистрация: 23.2.2006 Где: Гомель, Беларусь Репутация: нет Всего: 149 |
Я что угадал? У нас (в .Net) заголовок формы устанавливается через Form.Text Поля класса -- конретные "переменные" класса, т.е. его данные. Свойства -- "обертки" для полей класса, сделанные с помощью get и set. Врятли от языка к языку эти понятия меняются. Я ведь дал пример А вообще зайди IDE, выдели любой класс и любуйся открытыми СВОЙСТВАМИ в закладке Propertes. Там перечисленны только они, полей нет
А я что спорю
После нас хоть потоп. Да? Представьте ситуацию: Мы спроектировали класс, который что-то обрабатывает, а потом выводит на экран (ShowOnScreen()). Мы продали этот класс. Его используют другие люди. Всем нравится, все в восторге. Через некоторое время понадобился вывод на принтер. Они связваются с нами, мы лезем в код добавляем метод (SendToPrinter()). Через время понадобился вывод еще на что-нибудь... Это выход? Вместо того чтобы открыть результат вычислений, после чего любой сможет написать свой вывод на что угодно. О Вы вешаетесь на событие формы Resize, вам нужно перепозиционировать контролы на форме. Как это сделать, если размеры формы закрыты? Обожаю когда люди критикуют только часть сообщения, а не всё полностью Почему не было комментариев по этому поводу:
или |
||||||
|
|||||||
| En_t_end |
|
|||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 2074 Регистрация: 4.12.2004 Репутация: 1 Всего: 20 |
Мне ответьте |
|||
|
||||
| Daevaorn |
|
|||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 2155 Регистрация: 29.11.2004 Где: Москва Репутация: 51 Всего: 70 |
ivashkanet, Меня просто удивило, то что ты говоришь про стандартные классы и тут же про какие-то формы. В стандартном С++ нет форм. И пример просил привести именном поэтому. В стандартной библиотеке С++ надо постараться, чтобы встретить set/get, хотя найти можно.
А у меня в IDE нет такого. хнык-хнык Добавлено @ 16:51 Скорей всего по лигике этот класс сам должен эти данные записать в класс сборщика статистики |
|||
|
||||
| ivashkanet |
|
|||
![]() Кодю потиху ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 3684 Регистрация: 23.2.2006 Где: Гомель, Беларусь Репутация: нет Всего: 149 |
||||
|
||||
| Fazil6 |
|
||||||||||||
|
Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1653 Регистрация: 3.5.2006 Где: Минск Репутация: 35 Всего: 60 |
речь не о наз ваниях функций. Речь о данных, а не о свойствах. SetCaption это не установка переменной, хранящей значение заголовка, а именно изменение заголовка
вот и непонятно что именно и кому ты хочешь доказать...
вот об этом и речь - класс спроектировать надо было так, чтобы такая ситуация не возникала. причем добиться этого очень просто. Базовый класс Write. От него наследуются классы WriteInFile, WriteInScreen и т.д. Наш класс при в ф-ции вывода принимает указатель(или ссылку) на Write и вызывает виртуальные функции вывода. В зависимости какой дочерний объект был передан, туда и будет вывод. Для вывода кудато еще надо написать еще один класс вывода и все. Никаких изменений нашего класса не требуется, никакие данные класса нигде мной даже не упоминались. Вот это ООП... En_t_end,
Да нечего отвечать. Все уже написано выше. Данные класса не должны никого интересовать вне этого класса.
если единственная задача этого метода вернуть значение члена класса, то да, а если эта фукнция возвращает каким-либо способом объект, созданный на основе этих данных (например Visitor), то нет. Добавлено @ 17:07
это по какому стандарту?????? |
||||||||||||
|
|||||||||||||
| Daevaorn |
|
|||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 2155 Регистрация: 29.11.2004 Где: Москва Репутация: 51 Всего: 70 |
||||
|
||||
| Void |
|
||||||
![]() λcat.lolcat ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 2206 Регистрация: 16.11.2004 Где: Zürich Репутация: 40 Всего: 173 |
Что-то мне вспомнилась недоброй памяти ветка, где затрагивались вопросы инкапсуляции. В воздухе отчетливо запахло догмами…
Автор сказал именно то, что хотел сказать:
Не надо априори заворачивать все в get/set, и не надо априори считать открытый доступ к полям злом. Позволю себе привести цитату с одного форума, не совсем on-topic, но очень близко:
P.S. Солгасен с DeadSoul:
-------------------- “Coming back to where you started is not the same as never leaving.” — Terry Pratchett |
||||||
|
|||||||
| ivashkanet |
|
||||||||
![]() Кодю потиху ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 3684 Регистрация: 23.2.2006 Где: Гомель, Беларусь Репутация: нет Всего: 149 |
Поподробнее об это, пожалуйста. Что мешает мне в сеттере СВОЙСТВА Caption ПОЛНОСТЬЮ продублировать код функции SetCaption Или это опять нарушение инкапсуляции
Хророшо, но тогда получается, что он неправильно спроектирован? ОК, согласен. Но тогда все наши классы будут неподъемными монстрами, с КУЧЕЙ "лишнего" кода, который будет только заботиться о взаиможействии с остальным миром. Я получу, наконец, ответы на свои вопросы?
Заметьте, Form.Caption -- это не поле, а свойство, сделанное с помощью get и set, а в set помещен 1:1 код метода SetCaption и
|
||||||||
|
|||||||||
| Daevaorn |
|
|||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 2155 Регистрация: 29.11.2004 Где: Москва Репутация: 51 Всего: 70 |
В С++ нет такого лексического понятия как свойства! В это то собственно и весь топик, т.к. иногда приходится писать get/set Ты похоже со своим уставом монастырем ошибся;) |
|||
|
||||
| Fazil6 |
|
||||||||||
|
Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1653 Регистрация: 3.5.2006 Где: Минск Репутация: 35 Всего: 60 |
для того,чтобы в заголовке окна на экране поменялся текст недостаточно только изменить одну переменную в класе.
да???????
где у меня лишний код? Хочешь выводить файл на стену или в космос - пиши соответствующего наследника Write и все в шакаладе. Работавший до этого код никак не изменится и работа его никак не изменится
|
||||||||||
|
|||||||||||
| En_t_end |
|
||||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 2074 Регистрация: 4.12.2004 Репутация: 1 Всего: 20 |
Из выше сказанного есть вывод. Если использовать ООП, так как того требуют правила, то приходится проектировать ВСЮ функциональность в ОО-манере. Иначе поддерживать все правила инкапсуляции, сокрытия информации, метода "черного ящика" просто невозможно - всегда будет желание получить прямой доступ к полям классов. |
||||
|
|||||
| Fazil6 |
|
||||||||
|
Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1653 Регистрация: 3.5.2006 Где: Минск Репутация: 35 Всего: 60 |
пустые слова. Что мне мешает думать о фукнционале при разработке объектной модели? Пример тоже ни о чем не говорит.
ты неправ Добавлено @ 18:44
|
||||||||
|
|||||||||
| En_t_end |
|
||||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 2074 Регистрация: 4.12.2004 Репутация: 1 Всего: 20 |
Я наоборот считаю, что если сначала строить ОО-модель, то можно получить результат не только быстрей, но и качественне. Ты сразу накладываешь условие на некоторые параметры, подстраиваешь условия под возможности ООП, проектируешь с учетом ООП. Если же строить модель потом(я пробывал и так), приходится "обрезать" идею под возможности. Методом проб и ошибок, выбрал первое. Добавлено @ 18:59
я не это имел ввиду Это сообщение отредактировал(а) En_t_end - 8.7.2006, 19:06 |
||||
|
|||||
| Void |
|
||||
![]() λcat.lolcat ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 2206 Регистрация: 16.11.2004 Где: Zürich Репутация: 40 Всего: 173 |
ОК. Вот тебе линк на корень той дискуссии. Я не настаиваю на полной правоте этих слов.
По линку на ту ветку (в здешних РВ) сходил? Там тоже человек отстаивал антиобъектнориентированность геттеров/сеттеров и свойств, как синтаксического сахара над ними. Кстати, смысл есть и в закрытых или защищенных mutators. Уж они-то инкапсуляцию не нарушают, но иногда оправданны, т.к. повышают сопровождаемость кода. Это сообщение отредактировал(а) Void - 8.7.2006, 19:01 -------------------- “Coming back to where you started is not the same as never leaving.” — Terry Pratchett |
||||
|
|||||
| Fazil6 |
|
|||
|
Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1653 Регистрация: 3.5.2006 Где: Минск Репутация: 35 Всего: 60 |
там на другую тему дискуссия |
|||
|
||||
| ivashkanet |
|
||||||
![]() Кодю потиху ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 3684 Регистрация: 23.2.2006 Где: Гомель, Беларусь Репутация: нет Всего: 149 |
А кто говорит, что я собираюсь изменить только одну переменную? В сеттере я могу написать хоть сотню строк кода
Ага, читал. А то что вы сейчас имеете досталось вам от несовершенного C Монастырь агрономов-осеннизаторов? С какой такой стати? А не кажется ли, что ты все равно открываешь поле класса? Только делаешь это через вспомогательный класс Writer. Что мешает мне написать Writer который просто возьмет твое значение и будет с ним дальше работать? Что изменится? Ааа, наверное, создастся новая копия данных? Но это же я могу сделать и через сеттер (создать новый экземпляр данных) Полностью согласен с Void. Сеттеры и геттеры это синтаксический сахар, ИМХО. Сеттер -- более удобная (синтаксическая) замена функции типа void, принимающей один параметр. Геттер -- функции любого типа без параметров. |
||||||
|
|||||||
| Daevaorn |
|
|||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 2155 Регистрация: 29.11.2004 Где: Москва Репутация: 51 Всего: 70 |
||||
|
||||
| En_t_end |
|
|||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 2074 Регистрация: 4.12.2004 Репутация: 1 Всего: 20 |
||||
|
||||
| ivashkanet |
|
|||
![]() Кодю потиху ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 3684 Регистрация: 23.2.2006 Где: Гомель, Беларусь Репутация: нет Всего: 149 |
Повторяю: свойства -- это данные класса завернутые в get и set (неважно каким образом завернутые). Это просто пример класса у которого много открытых "данных". И как их закрыть я ума не приложу
Почитай внимательно первый пост Даже и не думал Добавлено @ 12:08 |
|||
|
||||
| Fazil6 |
|
||||||||||
|
Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1653 Регистрация: 3.5.2006 Где: Минск Репутация: 35 Всего: 60 |
ivashkanet,
в том то и дело, что ты неправильно себе представляешь тему изначально поднятую в топике и мало того - ты неправильно представляешь даже то, что пытаешься здесь доказать. Свойства - это не данные класса, это такая реализация интерфейса класса.
пример с формой не говорит, что это стандарт и так нужно делать всегда.
ничего ты не понял. Ничего здесь не открывается. Все можно делать правильно и неправильно. Вмоем примере каждый класс управляет только своими данными не требуя никаких данных у других классов, потому, что они ему просто не нужны, в этом и есть смысл этой ветки и большой части книги
И все таки, что мы такое сейчас имеем???? |
||||||||||
|
|||||||||||
| ivashkanet |
|
||||||||
![]() Кодю потиху ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 3684 Регистрация: 23.2.2006 Где: Гомель, Беларусь Репутация: нет Всего: 149 |
Поднятая тема -- не стоит использовать gettter и setter в коде? Или я не так понял, и поднятая тема -- не стоит использовать gettter и setter в коде, если они ничего не делает кроме как напрямую обращаются к данным? Как в примере.
Это врятли. Но то что я плохо изъясняю свою позицию --- с этим я могу согласиться
Нееее, эт я в курсе Забудь, я просто перефразировал автора.
Но таких классов не одна форма. Их сотни P.S. Предлагаю закончить ругаться |
||||||||
|
|||||||||
| likehood |
|
|||
|
666 ![]() ![]() Профиль Группа: Участник Сообщений: 536 Регистрация: 21.12.2005 Репутация: 8 Всего: 24 |
Вообще-то, SetCaption и есть сеттер для "свойства" Caption, куда ты собираешься дублировать код? В отсутствии свойств С не при чем, вон в C++ Builder'е свойства давно есть как расширение языка. Может в следующий стандарт их все же включат. |
|||
|
||||
| DeadSoul |
|
|||
|
Эксперт ![]() ![]() ![]() Профиль Группа: Участник Сообщений: 1217 Регистрация: 25.9.2005 Где: Москва Репутация: 2 Всего: 11 |
-------------------- Если Вы получили ответ на Ваш вопрос, то нажмите на "Вопрос решен". Бьем спамеров их же оружием. Пусть весь спам сыпется им [email protected] |
|||
|
||||
| ivashkanet |
|
||||
![]() Кодю потиху ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 3684 Регистрация: 23.2.2006 Где: Гомель, Беларусь Репутация: нет Всего: 149 |
Дя..., Это все отличие синтаксисов языков. Под SetCaption я имел в виду просто функцию, а не сеттер. Функциями ж типа можно пользоваться. А вообще, повторю свою позицию:
И никакой разницы между ними нет Добавлено @ 19:00 Как то странно: get и set есть, а свойств нет |
||||
|
|||||
| ivashkanet |
|
|||
![]() Кодю потиху ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 3684 Регистрация: 23.2.2006 Где: Гомель, Беларусь Репутация: нет Всего: 149 |
Как так?
P.S. Мог накосячить с синтаксисом, так как не в курсе про * и & (приведение к ссылке и назад). Но идея, думаю, ясна. |
|||
|
||||
| likehood |
|
|||
|
666 ![]() ![]() Профиль Группа: Участник Сообщений: 536 Регистрация: 21.12.2005 Репутация: 8 Всего: 24 |
||||
|
||||
| Fazil6 |
|
|||
|
Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1653 Регистрация: 3.5.2006 Где: Минск Репутация: 35 Всего: 60 |
ivashkanet
мда.... как все запущено.... ты бы почитал первые сообщения в этой ветке. Ну и что в том, что ты смог через открытый интерфейс получить значение данных. Если у тебя в классе есть необходимость в данных другого класса, то твой дизайн неправильный и об этом речь изначально, а не о том, что нельзя использовать set и get. В моем примере нет никакой необходимости в таких методах Это сообщение отредактировал(а) Fazil6 - 9.7.2006, 19:35 |
|||
|
||||
| ivashkanet |
|
|||
![]() Кодю потиху ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 3684 Регистрация: 23.2.2006 Где: Гомель, Беларусь Репутация: нет Всего: 149 |
А с ней (SetCaption()) нельзя делать вот так: Caption="Caption" Перечитал, ну и что? Меня возмутило то, как понял вас автор топика (а по другому вас понять невозможно Инициализация в конструкторе: А если у нас десяток полей (настроек класса) и все они необязательные? Делать конструктор на 10 параметров, или, еще лучше, 10! конструкторов на все случаи жизни. Методы "Распечататься", "Записаться в файл" и др.: Невозможно предусмотреть все варианты. А твой, Fazil6, пример ничем не лучше чем get или функции, возвращающей значение. А если цель моего класса -- обработать данные, то как мне их передавать? Наилучший выход метод Execute() или Calculate(), которые вернут вычисленное значение/структуру. А это ничем не лучше чем get |
|||
|
||||
| Daevaorn |
|
|||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 2155 Регистрация: 29.11.2004 Где: Москва Репутация: 51 Всего: 70 |
||||
|
||||
| Fazil6 |
|
||||||||||
|
Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1653 Регистрация: 3.5.2006 Где: Минск Репутация: 35 Всего: 60 |
именно. Именно это я и говорил. Именно так он меня и понял. Иэто правильно. Пользователь класса не должен задумываться о данных класса. Они его не интересуют.
изменить класс. Это плохой класс, если нужно создав класс начинать настраивать его установкой значений его переменных. Не надо только начинать мне приводить всякие классы форм из NET или VCL. Это не стандарт правильного проектирования классов всилу ряда причин. Сейчас разговор об объектно ориентированном подходе в теории.
Во первых перед программистом никогда не должна стоять задача предусмотреть все варианты. Перед ним стоит конкретная задача, а не некий гипотетический худший случай. Во вторых я привел тебе пример, когда классы разработаны так, что добавления нового функционала не затрагивают ни одной строчки работавшего до этого кода. И это правильно.
Причем здесь лучше или хуже? Я привел тебе пример того, что get и set вообще не нужныпри таком подходе, и это правильно.
бред какой-то. Ничего не понял. В моем примере Write как раз обрабатывает данные. Разве он говорит "дай мне вот эти свои данные и я их будуобрабатывать"? |
||||||||||
|
|||||||||||
| ivashkanet |
|
|||
![]() Кодю потиху ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 3684 Регистрация: 23.2.2006 Где: Гомель, Беларусь Репутация: нет Всего: 149 |
Забейте. Каждый остался при своем мнении.
Всем спасибо, что уделили мне время |
|||
|
||||
| Rockie |
|
|||
|
Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1143 Регистрация: 23.4.2006 Репутация: 8 Всего: 31 |
возможно повторюсь за Fazil6, но все-таки. я думаю здесь можно вспомнить The Dependency Inversion Principle - принцып иверсии зависимостей.
по сути он состоимт из двух частей:
и в пример приводится программа "Copy". модуль copy может читать с клавиатуры и записывать на принтер. ---- Copy----- | | Read Write Keyboard Printer а если понадобится читать из файла? или выводить не на принтер, а на консоль.. в этом случае рекомендуется делать так: ---->Copy<---- | | Abstract Abstract Reader Writer | | Read Write Keyboard Printer то есть в классах Abstr. Reader и Writer содержатся чистые виртуальные функции, и мы сможем добавить в систему "чтение из файла" или принтер другой модели, не трогая при этом Copy. предусмотреть 50 моделей принтеров действительно невозможно, но можно постараться сделать так, чтобы их потом можно было безболезненно добавлять. -------------------- Чтобы иметь большой гардероб - надо иметь большой гардероб. |
|||
|
||||
| likehood |
|
||||
|
666 ![]() ![]() Профиль Группа: Участник Сообщений: 536 Регистрация: 21.12.2005 Репутация: 8 Всего: 24 |
нет
Какая GUI библиотека является стандартом и что это за ряд причин? |
||||
|
|||||
| Leksey |
|
|||
![]() Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 332 Регистрация: 12.12.2004 Репутация: нет Всего: 1 |
А еще вопрос можно?
как реализовать класс Vector с тремя полями x,y,z не используя доступ к данным? Или его существование будет ошибкой проектировки? |
|||
|
||||
| Daevaorn |
|
|||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 2155 Регистрация: 29.11.2004 Где: Москва Репутация: 51 Всего: 70 |
Leksey, А чем этот Vector принципиально отличается от всего выше рассмотренного? Ничем, а значит и требования для него те же.
|
|||
|
||||
| Fazil6 |
|
||||||||
|
Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1653 Регистрация: 3.5.2006 Где: Минск Репутация: 35 Всего: 60 |
можно
напрягаешь голову, думаешь и реализовываешь
если он мне нахрен не надо в программе, то конечно это
|
||||||||
|
|||||||||
| UnrealMan |
|
||||||
|
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 722 Регистрация: 30.3.2006 Репутация: 27 Всего: 32 |
Даже если речь идёт о классе-наследнике? Т.е. код вроде
это уже ошибка проектирования?
Странный код, однако :-) Начнём с того, что непонятна природа SomeData. Что будут с ней делать функции write производных от Write классов? Кроме того, что мы будем делать, если нам понадобится не просто «распечатать» какое-то одно поле, а ещё и какие-то операции осуществить (причём, возможно, с несколькими полями)? Или все данные класса нужно непременно сосредоточить в одном-единственном поле d типа SomeData, и это есть хорошо? Ну это вообще шедевр, заслуживащий наивысших похвал :-) |
||||||
|
|||||||
| Leksey |
|
|||
![]() Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 332 Регистрация: 12.12.2004 Репутация: нет Всего: 1 |
Fazil6 А что так грубо?
Я вроде привел пример очень простого класса и просто интересно было посмотреть как его реализовать.А то может я что не так сделаю... |
|||
|
||||
| Fazil6 |
|
||||||||||||||
|
Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1653 Регистрация: 3.5.2006 Где: Минск Репутация: 35 Всего: 60 |
да. Это тоже самое, когда твои данные были бы просто protected Если DerivedClass оперирует данными, то почему эти данные находятся в другом классе. Данные класса - это деталь реализации, когда в наследовании принимают участия данные, то детали реализации становятся частью интерфейса, а это плохо.
никакого значения это не имеет. Это пример и это может быть все, что угодно. Не в этом смысл примера.
Вотм то и дело. Есть интерфейс и он определен
Классу по барабану, что вы будете делать с данными. Куда хотите, туда и выводите. Класс Сам решает какие данные он хочет вывести и передает их.
Опять пишем класс на на все случаи жизни? и что? Необходимость в доступе к данным == неправильный дизайн. Проектирование + виртуальные функции - вот инструмент решения проблем. Сколько еще раз повторить? Или Вы мне надеетесь доказать, что инкапсуляция куйня?
данные вне класса никому не нужны. Представьте себе функцию swap. Функция сидит себе и ничего не делает. Вдруг ее вызвали. Она получила 2 ссылки и поменяла их значения местами. Какое ей дело кто ее вызвал? Какое ей дело кто ей эти аргументы передал? По барабану что эти данные значат. Тоже самое происходит и снаружи этой функции. Когда кто-то вызывает функцию swap ему 100% до лампады как эта функция будет выполнять то, что от нее ждут. Она выдала результат и ауфидерзейн. Теперь представляем функцию, которая ходит за всеми и просит их дать ей 2 переменные и уж она их обработает. Бред. Почему по вашему с классами это не Бред? При хорошем проектировании вопросы, которыми вы пытаетесь меня победить не возникают вообще. UnrealMan,
а тут уж что тебя не устраивает? |
||||||||||||||
|
|||||||||||||||
| Fazil6 |
|
|||
|
Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1653 Регистрация: 3.5.2006 Где: Минск Репутация: 35 Всего: 60 |
тебе показалось. Ну писать тебе класс я не буду просто пото потому, что понятия не имею, что за класс тебе нужен. Обратись в центр помощи, может там помогут. |
|||
|
||||
| likehood |
|
|||
|
666 ![]() ![]() Профиль Группа: Участник Сообщений: 536 Регистрация: 21.12.2005 Репутация: 8 Всего: 24 |
Fazil6, в твоем первом примере с классом Write ты говорил, что нет необходимости давать доступ к внутренней структуре класса с помощью get/set? Если да, то твой пример ничего не объяснет, поскольку Write это абстракный класс, не содержащий никаких данных. Все данные передаются явно методу write, но откуда беруться эти данные? Если из другого класса, то здесь без get() не обойтись, а если это просто внешний объект, то причем здесь тогда инкапсуляция?
Может на более высоких уровнях абстракции и можно обойтись без get/set, то при реализации таких базовых классов как Point сложно обойтись без getX(), getY(), getZ(). Вообще, если класс представляет из себя некоторую структуру данных, то он далеко не всегда знает как эти данные обрабатывать. Тут одним наследованием и полиморфизмом не обойтись, предется открывать доступ к части данных. |
|||
|
||||
| Fazil6 |
|
||||
|
Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1653 Регистрация: 3.5.2006 Где: Минск Репутация: 35 Всего: 60 |
Добавлено @ 14:36
давайте всетаки не путать структуры данных и классы. Point - это всетаки данные, которые логически сгруппированы для удобства использования, а не класс. В структурах данных как раз интерес представляют сами данные и это совершенно другой вопрос. |
||||
|
|||||
| likehood |
|
|||
|
666 ![]() ![]() Профиль Группа: Участник Сообщений: 536 Регистрация: 21.12.2005 Репутация: 8 Всего: 24 |
А как класс Write получит доступ к данным SomeData?
С помощью get/set или того хуже SomeData - это структура с открытыми данными? |
|||
|
||||
| Дрон |
|
|||
![]() Java-ненавистник :) ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 3179 Регистрация: 29.12.2002 Где: Санкт-Петербург Репутация: 10 Всего: 93 |
baronp, не тут идея как раз в том, что для Write доступ к SomeData не нужен.
Наоборот SomeData использует Write и внутри себя подготваливает данные в том виде, в котором Write готов их принимать. Всё красиво в теории. Но "В теории нет разницы между теорией и практикой, на практике же она есть" (см. мою подпись). Никогда не поверю, что можно эффективно писать не интересуясь состоянием объекта до того, как потребовать от него действия. Вы же предпочтёте проверить сколько у вас денег в кошельке прежде, чем сделать дорогую покупку, а не говорить потом у кассы: "Ooops, an exception occured" Это сообщение отредактировал(а) Дрон - 12.7.2006, 15:53 -------------------- Да. Именно так. |
|||
|
||||
| likehood |
|
|||
|
666 ![]() ![]() Профиль Группа: Участник Сообщений: 536 Регистрация: 21.12.2005 Репутация: 8 Всего: 24 |
||||
|
||||
| Fazil6 |
|
||||
|
Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1653 Регистрация: 3.5.2006 Где: Минск Репутация: 35 Всего: 60 |
Повторяю : это абстрактный пример. Не важно что такое SomeData. Считайте, что это int. Вы за деревьями леса не видите.
Я - класс , деньги - мои данные. Я проверяю и ничего в этом страшного нет. Это ведь в классе происходит. А вот когда на просьбу показать товар, продавец потребует показать сколько у меня есть денег... Никого не должны интересовать мои деньги кроме меня. |
||||
|
|||||
| likehood |
|
|||
|
666 ![]() ![]() Профиль Группа: Участник Сообщений: 536 Регистрация: 21.12.2005 Репутация: 8 Всего: 24 |
То есть класс, содержащий данные должен знать о классах, которые будут эти данные обрабатывать (точнее, не о самих классах, а о интерфейсе Write). Если это библиотечный класс, то имхо будет сложно учесть в нем все возможные способы работы с его данными.
|
|||
|
||||
| Fazil6 |
|
|||
|
Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1653 Регистрация: 3.5.2006 Где: Минск Репутация: 35 Всего: 60 |
с его данными тоже никто работать не собирается. Никто не должен предусматривать все способы. Пиши те способы, которые нужны на данный момент. Если потребуется новый способ, ты напишешь новый класс, наследник Write реализуя интерфейс нужным тебе способом и все. С работавшим до этого кодом ничего делать не нужно. |
|||
|
||||
| likehood |
|
|||
|
666 ![]() ![]() Профиль Группа: Участник Сообщений: 536 Регистрация: 21.12.2005 Репутация: 8 Всего: 24 |
||||
|
||||
| Fazil6 |
|
|||
|
Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1653 Регистрация: 3.5.2006 Где: Минск Репутация: 35 Всего: 60 |
ну да, конечно. Но это ведь данные этого класса(наследника Write) и нигде кроме самого класса они не используются. А... Я понял о чем вы. В том смысле, что данные Write используются в его наследнике? Так это все из тойже оперы. Классы не должны наследовать данные (бывают конечно исключения но это исключения). Ведь я стою на принципе, что данные не интересуют никого вне класса в том числе и наследников. Почему тогда они наследуются? Если они не интересуют никого Я уже писал выше, плохо когда детали реализации становятся частью интерфейса между родителем и наследником |
|||
|
||||
| likehood |
|
|||
|
666 ![]() ![]() Профиль Группа: Участник Сообщений: 536 Регистрация: 21.12.2005 Репутация: 8 Всего: 24 |
что то я запутался: где у тебя храняться данные, которые надо вывести на печать или на экран?
в потомке Write или где-то еще? |
|||
|
||||
| Fazil6 |
|
|||
|
Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1653 Регистрация: 3.5.2006 Где: Минск Репутация: 35 Всего: 60 |
по моему очень простой пример. Функция write получает данные в аргументе от MyClass и куда-то их записывает. |
|||
|
||||
| likehood |
|
|||
|
666 ![]() ![]() Профиль Группа: Участник Сообщений: 536 Регистрация: 21.12.2005 Репутация: 8 Всего: 24 |
Еще раз повторю свой вопрос: как метод write получит доступ к SomeData.
В данном случае это принципиально, поскольку класс Write и его наследники не имеют своих данных, а служат лишь для обработки данных, полученных извне. Если SomeData это простая структура, то тогда причем тут полиморфизм, обращаемся напрямую к полям этой структуры и выводим все на печать. Если структура SomeData изменится, придется переписывать много кода. Если же доступ к SomeData идет через get/set, то есть надежда, что придется переписать только эти методы. Кстати, в данном первом примере вполне можно было обойтись без полиморфизма: просто наделать функции типа writeToFile, writeToPrinter и т.д. Как же тогда получить доступ к данным SetData без get/set и без нарушения инкапсуляции? |
|||
|
||||
| Fazil6 |
|
||||
|
Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1653 Регистрация: 3.5.2006 Где: Минск Репутация: 35 Всего: 60 |
еще раз повтаряю
Добавлено @ 23:02
ничего не понял. |
||||
|
|||||
| likehood |
|
|||
|
666 ![]() ![]() Профиль Группа: Участник Сообщений: 536 Регистрация: 21.12.2005 Репутация: 8 Всего: 24 |
Цель этого примера была конкретная: показать, что можно обойтись без меода get(). Я просто пытаюсь понять, действительно ли это так в данном "абстрактном" случае. Возможно, мы просто говорим о разных вещах. |
|||
|
||||
| Fazil6 |
|
|||
|
Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1653 Регистрация: 3.5.2006 Где: Минск Репутация: 35 Всего: 60 |
там разве где-нибудь есть такой или подобный метод? |
|||
|
||||
| likehood |
|
|||
|
666 ![]() ![]() Профиль Группа: Участник Сообщений: 536 Регистрация: 21.12.2005 Репутация: 8 Всего: 24 |
Fazil6, похоже мы и вправду говорим о разных вещах.
|
|||
|
||||
| UnrealMan |
|
||||||||||
|
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 722 Регистрация: 30.3.2006 Репутация: 27 Всего: 32 |
Нет, это не совсем то же самое.
А если эти данные нужны в обоих классах (BaseClass и DerivedClass) и они используются несколькими общими методами? Предлагаешь продублировать все эти данные и связанные с их обработкой методы?
Но интерфейс-то не открытый, а защищённый. А терять в общности, которую мы могли бы выразить с помощью защищённых данных и применённых к ним методов, – это хорошо? Эт я просто намекаю на то, что SomeData – это скорее некий универсальный тип, предназначенный для передачи данных в методы вывода, нежели тип поля класса (часто ли нужно выводить именно значение какого-то одного поля?). Т.е. метод output в MyClass должен преобразовывать члены-данные в данные вывода, которые дальше отправляются куда надо. Но тогда зачем вся эта возня с наследованием?
Укажи мне на какое-нибудь преимущество твоего способа перед тем, который только что продемонстрировал я. Забота о времени жизни каких-то левых вспомогательных объектов. Это сообщение отредактировал(а) UnrealMan - 13.7.2006, 12:02 |
||||||||||
|
|||||||||||
| Fazil6 |
|
||||||||||
|
Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1653 Регистрация: 3.5.2006 Где: Минск Репутация: 35 Всего: 60 |
UnrealMan,
из этого примера вообще непонятно, зачем нужен наследник. Я вам говорю, что методы get и set, наследование данных как правило свидетельствуют о плохом дизайне. Почти всегда можно сделать по настоящему ОО классы и на самом деле текста будет меньше и модель будет гибче и в сопровождении будет проще. А вы мне что отвечаете? "Нет! Доступ к данным необходим! Без него вот этот пример (здесь идет пример) не работает!" так я повторю - неправильный дизайн. Вот этот твой пример ничего не доказывает. Я вообще из него не вижу никаких резонов иметь родителя и наледника. Включи Method3 в родителя и все.
что значит зачем? код один и тот-же, но используется в зависимости от действительного типа аргумента. У меня для вывода может использоваться одна единственная (невиртуальная, неперегруженная, никак не переопределенная функция), а результат я буду получать в ней совершенно разный в зависимости от типа аргумента переданного в нее. Вот зачем наследование и полиморфизм. Теперь по поводу твоего последнего примера. Ржунимагу.
никакого. Ты написал абсолютно тоже самое, что писал я. Я могу конечно начать придираться к реализации (а есть к чему у тебя придираться и даже очень, особенно после Забота о времени жизни каких-то левых вспомогательных объектов. ), но сейчас мы говорим о другом. есть класс UserClass, у него есть данные. Но ведь у него нет методов get/set и ничего похожего на них. Вывод данных осуществляет сам класс UserClass, он решает что выводить. Где в твоем примере кому-то потребовались данные от UserClass? Все нормально. writer - это таже самая виртуальная функция по сути. Просто виртуальность ее ты сам обеспечиваешь. Ну пожалуста. А вот это
я вообще не замечаю. Если вокруг переменной нарисовать фигурные скобки и написать слово class, то классом эта конструкция не станет. Это в данном примере не класс, а структура данных, и как я писал выше тут смысл в самих данных и доступ к ним какбы очевидно должен быть, иначе что это за данные, которые я не могу видеть. Это тоже самое, что и SomeData в моем примере и если вас так сильно сбило всех с толку это слово то я уже писал, считайте это int или string или как хотите |
||||||||||
|
|||||||||||
| UnrealMan |
|
|||
|
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 722 Регистрация: 30.3.2006 Репутация: 27 Всего: 32 |
Ладно, приведу пример поконкретней. Пусть у нас имеется игра. В ней есть два вида персонажей: игрок (управляется пользователем) и монстр (управляется программно – простеньким искусственным интеллектом). Каждый персонаж обладает следующим набором свойств: положение в пространстве Pos, запас здоровья Health, запас брони Armor. Каждому персонажу можно нанести повреждение (Damage), проверить, не мёртвый ли он (IsDead), а также переместить в пространстве (Move) (каким образом – зависит от вида персонажа). Помимо этого, игрок обладает неким ограниченным количеством боеприпасов WeaponAmmo, а также может подымать аптечки (PickUpHealthPack) и броню (PickUpArmor) с поля боя, монстр же может атаковать неограниченно долго и не может подымать аптечки и броню. Интеллект монстра руководствуется неким своим текущим режимом поведения Mode (это может быть, скажем, яростная атака или стрельба в отступлении в игрока), а также запасом своих здоровья и брони (атаковать, когда много, отступать, когда мало). Вот примерный код:
Где тут «неправильный» дизайн? И как его сделать «правильным»? Ваш ход, сэр. Ну-ну, напихать в родителя всё, что только можно... Тогда действительно непонятно, зачем нужно наследование. Не понял. Если твои наследование и полиморфизм здесь ничего не дают (кроме лишнего геморроя с ворохом классов, для которых ещё нужно создавать объекты – по сути вспомогательные), то зачем вообще их тут было использовать? Давай-ка не будем наводить тень на плетень. Если бы всегда от наследования и (или) виртуальных функций можно было б освободиться так же легко, как это сделал я, смысл в их использовании был бы под сомнением. Я всего лишь клоню к тому, что наследование в твоём примере не нужно и только загромождает код, а следовательно, такой пример использования полиморфизма неудачен. Это сообщение отредактировал(а) UnrealMan - 14.7.2006, 09:26 |
|||
|
||||
| Fazil6 |
|
||||||||||
|
Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1653 Регистрация: 3.5.2006 Где: Минск Репутация: 35 Всего: 60 |
Ладно. Примем твою идею с общностью и необходимостью доступа к этим данным из наследников. Используем защищенный интерфейс. Хорошо. Избранный вариант самый гибкий, самый красивый, самый короткий и самый опасный. Это немногим лучше чем открытые данные. Этот интерфейс будет использоваться именно как доступ к переменным (ты так и пользуешься). Весь код использующий этот интерфейс становится зависимым от его реализации. Опять же, имя метода для установки значения Get - это плохой дизайн. Если уж делать, то
совсем не для того, чтобы размазывать реализацию по нескольким классам.
не думаю, что первоочередная задача программиста неиспользование виртуальных функций. Я не считаю, что твой способ без классов чем-то лучше, и посмотри на название ветки - это был не пример использования полиморфизма, а пример неиспользования доступа к данным. |
||||||||||
|
|||||||||||
| Meeer |
|
||||
|
Новичок Профиль Группа: Участник Сообщений: 20 Регистрация: 3.6.2006 Где: Ukraine Репутация: нет Всего: нет |
Вот почитал-почитал всю эту дискуссию.
Нам Rockie дает вырезку из какой-то книги. Как мы видим Fazil6 также читал (или читает) эту самую книгу, и
Fazil6 Я тебя понял. Но это в теории так идеально. А на практике довольно таки неудобно (судя из твоего примера там больше путаницы). Тем более всеравно те же самые значения передаются как параметр "ООП С++", автор Айра Пол, второе издание:
|
||||
|
|||||
| Fazil6 |
|
||||
|
Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1653 Регистрация: 3.5.2006 Где: Минск Репутация: 35 Всего: 60 |
пример чего?
странные вы какие-то люди. Вы, наверное, думаете, что я понятия не имею, что такое на практике ? Поверьте, я пишу программы и знаю, что то о чем я говорю, прекрасно без напрягов реализуется на практике. Особенно начинаешь это вспоминать при сопровождении (особенно чужого кода), при работе над проектом в команде Это сообщение отредактировал(а) Fazil6 - 15.7.2006, 20:07 |
||||
|
|||||
| UnrealMan |
|
||||||||||||
|
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 722 Регистрация: 30.3.2006 Репутация: 27 Всего: 32 |
Уж кто бы говорил... :-)
Вообще-то выбор между эффективностью+удобством и сопровождаемостью решается не в общем виде, а отдельно для каждого конкретного случая. Я допускаю оба способа.
Пока применительно к моей задаче ты не предложил ничего лучшего.
А «не забивать гвозди микроскопом» – это наверняка не первоочередная задача плотника. Тем не менее, разумный плотник скорее всего воспользуется для забивания гвоздей тем инструментом, который для этого предназначен. В данном случае для вызова нужной (конкретной) функции посредством явного её указания уже существует механизм – вызов через указатели на функции. Виртуальные же функции тем и хороши, что избавляют от необходимости указывать конкретную фунцию явно (и именно в этом их предназначение).
Это как раз ты используешь виртуальность не по назначению, обеспечивая тот же эффект, что и при вызове функций через их явно прописанные в исходниках указатели.
С этой точки зрения дела обстоят не намного лучше :-) Что показывает твой пример? Не может ли, скажем, оказаться, что иногда нам придётся формировать данные вывода, которые при выводе каким-то способом вообще не будут использоваться (а нам всё равно надо будет по-честному заполнять всю структуру данных вывода – иначе при каком-нибудь другом виде вывода недополучим какую-то информацию)? |
||||||||||||
|
|||||||||||||
| Fazil6 |
|
||||||||||||
|
Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1653 Регистрация: 3.5.2006 Где: Минск Репутация: 35 Всего: 60 |
UnrealMan,
плохой дизайн вынуждает идти на компромис. Эфективность и сопровождаемость не взаимоисключающие.
не собирался и не собираюсь. Не собираюсь тебе ничего доказывать.
я и не пытался ничего явно указывать. Наоборот, я полностью скрыл всю реализацию и там, где непосредственно вызывается функция с передачей ей указателя объекта для вывода совершенно необязательно известно куда будет производиться вывод. А писать цепочки вызовов, чтобы продемонстрировать, что в месте вызова
причем здесь формирование данных для вывода? Где у меня в примере формирование данных? Что вы прицепились к структуре данных? Чем твой пример в этом плане от моего отличается? Разве я как-то поразному использую в MyClass данные для вывода?
мой пример показывает, что для обеспечения вывода данных класс MyClass должен знать , что есть класс Write для вывода и знать его интерфейс и все. И таких классов как MyClass может быть сколько угодно, и они могут быть никак между собой не связаны. Write о них ничего не знает, а они друг о друге. А если подходить с точки зрения когда класс вывода будет запрашивать данные у класса и выводить их, то каждый класс(либо просто функция, как тебе удобнее) вывода куда попало, должен знать все эти классы и их интерфейсы, да еще и функции должны быть перегруженные, если все эти классы выдающие данные не связаны наследованием. Это смысл моего примера. И мне непонятно какого ражна вы цепляетесь к деталям типа, что такое SomeData, откуда это берется и что это такое. Строка это. |
||||||||||||
|
|||||||||||||
| UnrealMan |
|
||||||||||||
|
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 722 Регистрация: 30.3.2006 Репутация: 27 Всего: 32 |
Что, при виде нетривиальных задач сразу в кусты? :-) Тогда к чему все эти твои пустые разговоры про «плохой дизайн»? А это тогда что?
Явное указание функции заменили явным указанием объекта, который ассоциирован с нужным классом, который в свою очередь ассоциирован с нужной функцией. Да, необязательно явно указывать требуемый способ вывода именно в месте вызова mcl.output – это можно сделать раньше, и между явно указанными способами можно делать выбор на этапе выполнения программы (см. мой пример с функциями в пространстве имён Output) – и будет тогда твоё
Но речь-то не идёт о том, где мы размещаем явное указание требуемого способа вывода, – факт в том, что явное указание имеет место.
Ну правильно, зачем же тебе рассматривать задачи, где могут возникнуть затруднения, когда можно продемонстрировать решение какой-то тривиальной задачки – дабы подтвердить какие-то твои тезисы? :-) Мой пример призван: 1) уточнить, чем станет твоё SomeData в случае, когда требуется сформировать данные вывода; 2) показать, что полиморфизм в таком виде тут не нужен. Насмешил :-) В твоём классе вывод юзает только одно поле данных – d (причём без какой-либо обработки со стороны класса MyClass). Как часто приходится сталкиваться с таким случаем в реальной практике?
На тебе то же самое:
Только теперь я смогу для каждого типа вывода сформировать свои данные (необходимые и понятные именно для него), а не отправлять каждый раз полный джентльменский набор на все случаи жизни. Это сообщение отредактировал(а) UnrealMan - 16.7.2006, 18:55 |
||||||||||||
|
|||||||||||||
| Fazil6 |
|
||||||||||||||||||||
|
Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1653 Регистрация: 3.5.2006 Где: Минск Репутация: 35 Всего: 60 |
пример с потолка.
если ты не понимаешь смысл того, что я сказал - это твоя проблема.
какое это имеет значение в данном вопросе? а это вообще бред какой-то Вопрос
ответ
совсем не тоже самое.
интересно какую ерунду ты писал бы, если бы я вместо SomeData написал int... |
||||||||||||||||||||
|
|||||||||||||||||||||
| Meeer |
|
|||
|
Новичок Профиль Группа: Участник Сообщений: 20 Регистрация: 3.6.2006 Где: Ukraine Репутация: нет Всего: нет |
Господа, это лишняя трата времени и нервов. По-моему все равно каждый останется при своем мнении. Прекращайте!
|
|||
|
||||
| likehood |
|
||||||||
|
666 ![]() ![]() Профиль Группа: Участник Сообщений: 536 Регистрация: 21.12.2005 Репутация: 8 Всего: 24 |
Сейчас объясню, но для этого придется вернуться к началу беседы: Здесь имелось ввиду, что спроектированный класс (для определенности назовем его Renderer) сам производит нужные вычисления, сохраняет их результат в своих закрытых полях, и сам же выводит все это на экран. Почему Rendedrer сам делает весь вывод, хотя логичнее было бы поручитьт его другому классу (Writer'у)? Да потому что нам нельзя использовать геттеры, а как иначе Writer получит доступ к закрытым полям класса Renderer (и эти поля отнюдь не сводятся к одному единственному string'у). Ведь нельзя же нарушать инкапсуляцию! Остается единственный выход: сделать в базовом классе Renderer абстрактную ф-ю write, которую можно переопределить в классе RenderToScreen, при этом данные в Renderer'е придется сделать защищенными (protected), иначе как получить к ним доступ (здесь мы еще не знаем, что protected - это тоже плохой дизайн, Fazil6 сказал об этом лишь несколько десятков постов спустя). Отсюда и фраза:
ведь тогда надо будет в базовом классе позаботиться не только о выводе данных, но и обо всем остальном, что можно с этими данными делать. Только Fazil6 не увидел здесь никаких проблем: и в последовавшем примере продемонстрировал всю силу ОО-полиморфизма. Пример неплохой, вот только куда там делся класс Renderer? Нет, конечно суть примера была продемонстрировать как можно изменить структуру программы (при этом класс Renderer мог вообще исчезнуть), но ведь поведение программы должно остаться тем же: кто-то вычисляет исходные данные, которые где-то храняться, их кто-то потом выводит на экран. Вот только класс Write (да и его потомки) не содержат никаких данных. Значит они берут эти данные из параметра SomeData (а откуда их иначе брать), который в таком случае вполне может играть роль класса Renderer. Но не тут-то было: на вопрос "что это за SomeData такое" последовал ответ:
Ну все, приехали! Как это не имеет значения! Если цель была продемонстрировать всю силу виртуальных функций, то может и не имеет, а если как избавиться от get/set, то это принципиальный момент. Похоже, Fazil6 пошел по первому пути, отсюда и все дальнейшие непонятки. Людям то охото узнать как Writer берет чужие данные без геттеров, не нарушая при этом инкапсуляцию, а Fazil6 пытается при этом доказать что-то другое. Может то что он говорит и правильно (так оно и есть), но только разговор этот немного "не по теме". Такое впечатление, что методу write все равно откуда приходят данные, а SomeData это просто сокет, из которого идет поток байтов. Короче говоря, из этого примера я так и не понял как можно обойтись без геттеров в данном случае, но судя по тому, что
это все же можно сделать и было бы неплохо это увидеть. |
||||||||
|
|||||||||
| Fazil6 |
|
|||
|
Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1653 Регистрация: 3.5.2006 Где: Минск Репутация: 35 Всего: 60 |
Например Write в ф-ции write принимает массив строк. Его потомки умеют записать этот массив строк в файл или принтер или на экран или еще куда. Вот класс имеющий данные передает этот массив в функцию write. Параметр, передаваемый в write - это не класс, это данные. |
|||
|
||||
| likehood |
|
|||
|
666 ![]() ![]() Профиль Группа: Участник Сообщений: 536 Регистрация: 21.12.2005 Репутация: 8 Всего: 24 |
Fazil6, вы хотите сказать, что класс MyClass вместо того, чтобы открывать доступ к своим данным сам выбирает, кому он будет передавать эти данные и в каком виде? На счет того, что ф-ии write передаются данные, а не класс, то здесь наверное имеется ввиду, что это может быть и структура если данные довольно сложные, но в данном случае использование структуры с открытыми полями не будет нарушением инкапсуляции (можно было сделать ф-ю с 10-ю параметрами, но структура удобнее)? Класс MyClass отвечает за обработку и хранение данных, а если понадобиться сделать с данными что-то еще кроме вывода, можно просто добавить в MyClass еще один метод (не обязательно виртуальный) и в данном случае это не преведет к большим изменениям в программе? Я правильно понял мысль?
|
|||
|
||||
| skyboy |
|
|||
|
неОпытный ![]() ![]() ![]() ![]() Профиль Группа: Модератор Сообщений: 9820 Регистрация: 18.5.2006 Где: Днепропетровск Репутация: 1 Всего: 260 |
вот именно! только место "нельзя" я бы поставил "нежелательно". Категоричность - плохой друг и подлый враг. А касательно данных... Данные формируются в классе Render. Так? Если выводятся им же(или его потомками), то инкапсуляция ненарушена: логика и формирования изображения(первоначальная функциональность) и вывода его на принтер(добавленный метод) в пределах одного класса. Изменим один метод(его логику, структуру опериуемых данных) изменим и другой. А если будем использовать другой класс для вывода, как нам дать понять, что данные имеют другую структуру/формируются по-другому? Getter будет вместо данных возвращать надпись "проверьте свой класс"? Или писать два разных метода рендеринга(под старую логику и новую) и два новых getter'a с разными именами(под данные старой структуры и новой)? Какой вариант предпочтительнее? Когда класс и его потомки вполне самодостаточны или когда один класс "почти универсален", но универсальность эта - липовая и достигается экстенсивными методами? |
|||
|
||||
| Fazil6 |
|
||||
|
Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1653 Регистрация: 3.5.2006 Где: Минск Репутация: 35 Всего: 60 |
Это сообщение отредактировал(а) Fazil6 - 17.7.2006, 01:32 |
||||
|
|||||
| likehood |
|
|||
|
666 ![]() ![]() Профиль Группа: Участник Сообщений: 536 Регистрация: 21.12.2005 Репутация: 8 Всего: 24 |
"куда" - имеется ввиду методу с определенным прототипом. Все же если мы пишем класс "на все случаи жизни", то придется предусмотреть множество (в смысле много) операций над данными в самом базовом классе (или если хотите набор прототипов виртуальных ф-ий), что приведет к разрастанию интерфейса класса. Если этот класс библиотечный, предусмотреть все операции над данными будет очень сложно, потому то в GUI классах сложно обойтись без геттеров/сеттеров. это было сказано с долей сарказма, категоричность мне вообще не свойственна. |
|||
|
||||
| UnrealMan |
|
||||
|
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 722 Регистрация: 30.3.2006 Репутация: 27 Всего: 32 |
Отмазки в рассмотрение не принимаются.
Объясняю на пальцах. Пусть у нас есть классы Class1 и Class2, данные которых нужно выводить. При выводе на экран данных Class1 и Class2 не требуется никаких действий со стороны пользователя, однако при выводе данных Class1 в файл пользователю предлагается в диалоговом окне выбрать путь и имя файла для записи. В свою очередь для вывода в файл данных Class2 от пользователя никаких действий не требуется – объект класса сам предоставляет нужный путь и имя файла. Ну и что ты будешь делать со своим SomeData? А если нам ещё третий класс предстоит разработать – тоже со своими условиями, – что будет тогда? Не такая уж красивая картина получается, правда? Это не бред, а напоминание – на всякий случай (только не говори, что у тебя, кроме твоего кода, про ООП больше нигде ничего не упоминалось).
Ту часть, которая передаёт нужную информацию в объекты классов из ::Output, – да; классы для вывода в ::Output – нет. Только давай уточним насчёт «переписывать»: если у нас идёт обработка данных перед выводом, то нам всё равно придётся где-то её размещать – внутри класса или вне (например, внутри пространства имён UserClass1_::Output). Вообще же класс лучше было бы назвать LibraryClass (LibraryClass1) – дабы подчеркнуть, что каких-либо изменений в него мы уже внести не сумеем – придётся или довольствоваться тем, что есть, или же переписывать весь класс заново (и, возможно, менять все старые объявления объектов). Были бы те же самые проблемы + необходимость для каждого типа писать свой метод write (в классе Write и его наследниках) – кстати, только тогда полиморфизм и будет уместен. Что-то я не понял, как это даст получить доступ к этим данным. Приведи пример. Зависимость от реализации тут ни при чём. За классом изначально могут быть закреплены нужные (по условию задачи, которую решает данный класс) неизменные свойства, которые вполне логично задавать в виде полей. Можно было бы считать такой класс структурой данных в стиле C, но тогда определение структуры данных в стиле C пришлось бы сильно притягивать за уши, ибо внутреннее устройство этого класса может быть столь же сложным, как и в любом другом классе, где все члены-данные не являются некими хранилищами свойств, диктуемых в отношении класса условием задачи. Это сообщение отредактировал(а) UnrealMan - 17.7.2006, 12:46 |
||||
|
|||||
| Meeer |
|
|||
|
Новичок Профиль Группа: Участник Сообщений: 20 Регистрация: 3.6.2006 Где: Ukraine Репутация: нет Всего: нет |
Я всю тему прочитал с начала, и для меня, как наблюдателя (с большей стороны), более убедительная позиция выглядит со стороны "использования get-ов", т.к. получается код гибче. И это неплохая довольно-таки привычка(на мой взгляд). Правила существуют что бы их нарушать (всем известно). Можно конечно его и придерживаться (правила). Это решать каждому.
|
|||
|
||||
| UnrealMan |
|
||||
|
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 722 Регистрация: 30.3.2006 Репутация: 27 Всего: 32 |
Только в отношении свойств, закреплённых за классом условием задачи. Например, возьмём тот же класс строк STL basic_string и посмотрим на одну из реализаций length():
По сути length – тот же get (можно было бы назвать этот метод «Get_Len»), получающий жёстко закреплённое за строкой свойство – длину. Никакого нарушения инкапсуляции тут нет. В остальных же случаях использования get/set следует избегать. |
||||
|
|||||
| maxzone |
|
|||
|
Новичок Профиль Группа: Участник Сообщений: 2 Регистрация: 15.8.2006 Репутация: нет Всего: нет |
Очень жалко, что я не успел во время к этой (и более ранней аналогичной теме ) теме.
Очень понравилось сравнение себя как класса, стоящего в супермарке в очереди к кассиру: Не дело это - самому кассиру залазит в мой кошелек и вычитать из того, что он там нашел Он просто должен сказать: "С вас столько-то!" (object.Pay(X dollars)) 2-ой вариант, действительно, отражает характер ООП. А вдруг у меня денег не хватит, тогда (во 2-ом случае, когда данные не выствленны наружу) я могу ну, например, делегировать оплату стоящему с зади меня другу с большим кошельком Пофантазируем еще, во мне, как в классе, а точнее в моем кошелке, появляется новое поле - КРЕДИТКА! (не являющейся наличкой как бы) Что мы делаем в 1-ом случае? Правильно, вводим гетеры/сеттеры для нового поля. А кассир что? Правильно. Теперь он лезет ко мне в карман считает деньги, принимает решение, что денег не хватает, смотрит что есть кридитка и т.д. (В прочем, вариант с делегированием другу опять может остаться в стороне) А во 2-ом случае? Да н_и_ч_е_г_о. Данные скрыты(Свойств, если вам так удобнее, нет). Это мое внутреннее дело, как я буду оплачивать Конечно, можно сказать, что это пример надуманного ООП, и геттеры/сеттеры здесь притянуты за уши (гм, разве?), но лучше я посоветую прочитать ответ на поставленный здесь вопрос, почему get/set не есть хорошо в книжке (C++ Gotchas: Avoiding Common Problems in Coding and Design by Stephen C. Dewhurst ) Она представляет из себя сборник из 100 наиболее распространненых ловушек, куда попадают программисты на с++ (по моему Gotcha N67, но могу и ошибаться). Не буду гнуть пальцы и кричать, как? вы не знаете кто такой Дьюхарст.. Просто советую. Тем более, что эта книга уже переведена на русский язык... |
|||
|
||||
| akizelokro |
|
|||
![]() Крокодил ![]() ![]() Профиль Группа: Участник Сообщений: 761 Регистрация: 30.7.2007 Репутация: 1 Всего: 5 |
Предлагаю посмотреть с другой стороны.
С++ нужен для работы программерского коллектива. Отсюда и большинство требований. Так что не парьтесь. Есть дядька, который будет вам расписывать задание на класс. Ваше дело будет выдать ему код в конце рабочего дня. Дальше код пойдет к другому программисту, который не особо будет вникать в вашу начинку. Он воспользуется вашим классом и его методами. Отсюда и требования, чтобы было поменьше дыр, которые дадут вашему коллеге воспользоваться незадокументированной вами возможностью и чего-то там навернуть лишка в данных. Сами вы можете писать на чем угодно. На асме или на сях. В одиночку большую программу не поднять, так что вы можете для себя прописывать даже просто структуры вместо классов. С++ конечно облегчил жизнь в "одиночном программировании", но, иной раз вы залазите в конкретную тину, о которой вам даже думать не надо. И мне тоже. Кстати, С++ тоже не идеал... как показала жизнь. И даже проблема не в наследстве сей. В один момент процесс пухнет. И где там при наследовании классов лишнее сработает не туда.. Рассказать, как я три дня просто у себя искал тупую ошибку в for() и не мог ее увидеть? Просто не верил, что она может быть именно там. -------------------- a = a + b; b = a - b; a = a - b; |
|||
|
||||
| ivashkanet |
|
|||
![]() Кодю потиху ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 3684 Регистрация: 23.2.2006 Где: Гомель, Беларусь Репутация: нет Всего: 149 |
P.S. akizelokro, ИМХО, ты прав, но не надо было разжигать спор опять |
|||
|
||||
| Daevaorn |
|
|||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 2155 Регистрация: 29.11.2004 Где: Москва Репутация: 51 Всего: 70 |
к счастью не все работают кодерами, а некоторые всё-таки программисты и и более "думающие спецы", поэтому не всегда кто-то водит тебя за руку. |
|||
|
||||
| akizelokro |
|
|||
![]() Крокодил ![]() ![]() Профиль Группа: Участник Сообщений: 761 Регистрация: 30.7.2007 Репутация: 1 Всего: 5 |
Тогда ты сам должен понимать, что не всем правилам нужно следовать в 100% случаев. Они, правила, гораздо интереснее своими исключениями. А тогда окажется, что и какой-то get/set будет гораздо более по теме. А в общем, приведенном в теме смысле, думающие спецы давно бы привели конкретный пример, когда постоянное использование get/set осложнило бы работу при наследовании классов, когда делают дело разные программисты. Эхмы, мой неконкретный опыт мне только подтверждает постоянную сферу действия законов паркинсона и др. и др. Если полазить раньше по этой теме, то можно было найти вопрос о том, что любой класс нуждается в функции GetOccupied. Это, на мой взгляд, неправильно. Для этого пишется общий предок (либо виртуальный класс, либо класс с виртуальным методом,- четыре года ничего не писал, пошел Страуструпа чтить и искать различия между первоначальным стандартом и практической реализацией стандарта). -------------------- a = a + b; b = a - b; a = a - b; |
|||
|
||||
![]()
|
| Правила форума "С++:Общие вопросы" | |
|
|
Добро пожаловать!
Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Earnest Daevaorn |
| 0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей) | |
| 0 Пользователей: | |
| « Предыдущая тема | C/C++: Общие вопросы | Следующая тема » |
|
|
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности Powered by Invision Power Board(R) 1.3 © 2003 IPS, Inc. |