![]() |
final или не final
Использовать ли final при объявлении чего-либо. В одних источниках я читал, что это загружает код, в других - что делает его быстрее, так как его нельзя продолжить. Стоит ли его использовать постоянно? А не только тогда, когда необходимы специальные классы и функции, которые нельзя наследовать.
|
я бы предпочел вообще обходится без final, так работать интересней
|
Иногда необходимо, чтобы классы нельзя было расширить. Так часто делает и сама Adobe почти со всеми классами.
|
Можно поприменять при использовании "Шаблонного метода", чтобы не спутать какие методы предназначены для перегрузки а какие нет.
А целый класс финалить, чтобы нельзя было расширить - зачем это может понадобиться? Только если вы хотите намекнуть коллегам: "Не ребят, даже не пытайтесь, этот класс безнадежен, он чудом вообще работает и если вы хотите на нём что-то построить - то это будет генератор багов" А, более адекватная причина: Класс A используется в классе B хитрым образом с завязкой на реализацию именно этого класса А и если в класс B вы попытаетесь подставить наследника класса А - он развалится нафиг. Так что не пытайтесь. Короче, final-изация класса применяется, когда есть проблемы с дизайном. Цитата:
Может потому, что тестировал на дебажной версии флешплеера (сборка swf-ки была релизная) Целиком финализированный класс не тестил. |
Lyso, это вы автор топика This или не this?
Вопрос риторический... Знаете, не в обиду конечно, но складывается впечатление что вы там где-то открываете для себя новый оператор, ранее незнакомый, и решаете поспрашивать о нем на форуме. Так вот, ТАМ где вы узнали про этот оператор должно было рассказываться для каких целей он применяется. Если хотите чтобы наследовался - не пишите final, хотите обратного - пишите. Или вы пытаетесь найти в операторе final подвох или спасение? Там нет ни того ни другого, просто конкретная функциональность. P.s. Adobe НИКОГДА без причины не закрывают возможность наследования того или иного предопределенного класса. |
Цитата:
Например, представьте себе следующую ситуацию: некоторый класс A является DataProvider`ом для класса B. Класс B честно ждёт загрузки данных (события Event.COMPLETE), после чего мирно начинает работать. Но злые гномы подсунули вместо класса A его наследника, ExtendedA, который шмаляет этот самый Event.COMPLETE каждую секунду. Мирного экземпляра класса B увозят в психушку. Занавес. Примерно для таких ситуаций и нужен final. Но я сторонник того, что бензопила круче лобзика, и то что к первой надо читать инструкцию и думать меня не останавливает. Поэтому final я не пишу никогда. P.S. final на скорость никак не влияет. Это даже наивно думать, что компилятор делает какие-то "преобразования", закрывая "отросток" (таблицу виртуальных функций, видимо), который позволяет получить прирост в скорости. Даже если бы такое закрытие существовало - компилятор бы находил сам финальных наследников и перед компиляцией помечал бы их как final. final — это самозавязка рук, и не более. |
Типичая ситуация, когда нужен final - тогда же, когда бы вы, например, использовали константу. Объекту очень редко нужны такие методы (мне ни разу не понадобились), как и не-статические константы (такими, как ни странно, часто пользуюсь, но в целом это не общепринятая практика). А статические / функции объявленные вне класса и так по факту final.
Я объявляю как final приватные классы (т.е. классы объявленные в том же файле, но вне пакета) не чтобы запретить наследование, а чтобы констатировать факт, что наследовать их уже никак не получится (для документации). |
Цитата:
Есть парадигма проектирования (запамятовал название), согласно которой любой класс должен быть либо абстрактным, либо финальным. Если класс абстрактный -- он специально спроектирован под расширение. Если класс финальный -- мы можем не заботиться о том, что кто-то может заоверрайдить метод и нарушить всю логику. Мне случилось пару лет поработать с принципиальными сторонниками этого принципа. По результатам могу сказать, что в больших проектах это существенно повышает стабильность. Если же в одиночку за неделю пишется проект на два десятка классов, то словом "final" можно не заморачиваться. |
Классная парадигма, однако. Т.е. запрещаем цепочки наследования больше 1-го яруса на уровне соглашения по кодированию :) Но что-то глядя на flex-фреймворк кажется что такое невозможно. Да и в Qt говорят длиннющие цепочки наследования.
Неужели заставить кодеров не выбиваться за 1 ярус наследования реально? Цитата:
Код AS3:
Код AS3:
да и такие оптимизации в идеале должен компилятор делать - у него для этого достаточно информации: http://gskinner.com/talks/quick/#47 |
Цитата:
|
Можно вообще все только статическими методами написать :)
EDIT: а, не, не получится стейдж получить, а так бы можно было :) |
Конечно можно, а еще можно просто на джаваСкрипте фигачить, чего уж там, нам ооп вообще ненужно! =)
|
Вот так вот, java-script уже не ООП-язык
|
expl, ну что вы. Просто я осветил стадии деградации. Сначала переходим на жава скрипт, а потом и вовсе бросаем ооп.
|
Цитата:
|
Цитата:
|
*** honest_man в страхе быть забитым любителями JS. =)
Цитата:
|
Цитата:
Добавлено через 11 минут Цитата:
Разделение abstract-final позволяет это упорядочить. Если пишется abstract-класс -- автор заранее пишет его под наследование. Соответственно, при внесении изменений в абстрактный класс нельзя тупо забыть, что от него наследуются. P.S. Вообще, следует понимать, что наследование реализации -- довольно опасная операция. |
Цитата:
Как по мне, в данной ситуации, это рефакторинг - опасная операция. А может просто программист А поссорился с программистом В? |
Цитата:
Когда надо получить класс с похожим функционалом обычно от него никто не наследуется, а выносят базовый класс для обоих. Так просто проще. А тут их просто еще финалят для верности. Цитата:
Цитата:
Все зависит от количества кода, использующего класс А, который собираешься рефакторить (будет печально, если ты отломал что-то в общей либе и упало приложение, разрабатываемое вообще другой коммандой) и от количества тестов для этого класса А, которыми сможешь проверить что ничего не отломал. А если этот класс А использует 2-10 классов только в этом приложении, которые можно быстро протестить - грешно не отрефакторить Цитата:
|
Цитата:
Хотя с другой стороны программист А тоже хорош, пусть не мешает личное с делами... Уволить обоих! И нанять программистов C & D! |
Цитата:
Есть еще такой момент - я, (все еще) почему-то предполагаю, что человека, который будет использовать мой код возможно заинтересует реализация, и при наследовании он не будет делать каких-то явных глупостей. Увы, так не работает. И если необходимо получить результат не взирая на "идиотов" сотрудников, которым жалко лишний раз посмотреть чужой исходник... да, иногда наверное не помешает и final... |
Цитата:
Где-то с год назад мне довелось поработать с кодом большого сторонника модульных тестов. Покрытие -- свыше 95%. При этом "работа над ошибками" показала, что в оставшиеся 5% аккуратно вошли разные аномальные состояния. Тесты -- работают. А если вдруг из стороннего модуля исключение прилетит -- вся система в алмазный дым обращается. А юнит-тестов при этом -- процентов на 20 больше, чем "полезного" кода. Цитата:
Цитата:
|
Да, я о другом :)
Вот, непридуманная ситуация, буквально пару дней назад. Был у меня класс, в котором была переменная хранившая XML. Этот класс должен был использоваться другим человеком. Если занулить / не инициализировать переменную, то были бы ошибки, и очевидно поэтому человек использовавший мой класс решил сделать следующее: _xml = new XML() (и заработало, но не совсем...). Я не предполагал, что XML в этом месте может быть не элементом, а текстом, например. Я когда увидел, чуть не заплакал. Переделал переменную в константу - стало менее удобно, но без ошибок. Ну а если я что-то поменял в моем классе, что потенциально приведет в нерабочее состояние чужой код - ну так я, чисто по-человечески должен хотя-бы в коммит-лог об этом написать. Опять же, юнит тесты с большой вероятностью покажут, что я что-то сломал, если сломал. Ну и я делаю так: public и protected, если я меняю, я дописываю [Deprecated] и оставляю так на несколько версий, пока все не переделают под новый вариант. То, что я не предполагаю, что другие будут использовать - private / internal. Если кто-то использовал internal - на свой страх и риск, и если не работает / перестало - не мои проблемы. |
Цитата:
Хотя с другой стороны, эти 10 тестов, в которых ни слухом - ни духом о реальном, не замененном моком синглике - могут однажды повести себя неадекватно. |
Цитата:
...то синглетон для этого не нужен. Применяемая для этого конструкция похожа, но не имеет к синглетону никакого отношения. |
Имеете в виду статическую фабрику?
Код AS3:
|
expl.
ОК, пример :) Код AS3:
|
Ага, как обломали подавана, понятно (ох, как я часто от коллег слышу "А давай этот класс сделаем синглтоном" - хочется увесистой книжкой по пальцам сразу).
А вот как вы ссылки тянете на эти сервисы в клиентские классы не очень. Например есть модель: - Юзер --деревня ---грядка Главный контроллер (его я даже не пытаюсь покрыть unit-тестами - он завязан на все и вся, но сложной логики там мало, большинство делегируется его детям и модели) инштанцирует СинхронизаторВремениССервером. Если передавать его всем детям в стиле "push" получается: - надо протащить ссылки через Юзера и деревню - надо каждый раз передавать грядке синхронизатор при ее добавлении Получается лезем в тесты Юзера и деревни, чтобы добавить в конструктор этот сервис (допустим, он нужен только грядке) То что в тестах деревни может что-то зависеть от синхронизатора, который находится в Грядке - это другой вопрос. |
К сожалению, в реальном проекте взаимодействие между частями - это вотчина падавана (он там работает на 2 года больше меня, и мне поэтому ничего "серьезного" не доверяют... ну так вот :)). На то, что там происходит без слез / смеха смотреть тяжело... Так что, как "у нас", уж наверняка лучше не делать.
Так, как я бы делал - иерархия, ребенок сообщает наверх, и не его забота кто и как обработает, даже ни на что не подписывается, когда надо будет, ему родитель "скажет" что делать. |
По поводу "идеалистического" подхода
Вот есть ребенок, у его родителя есть на него ссылка и родитель может принимать от него события Если ребенка пнули или изменили - что делать ясно - посылать событие - родитель, или кто повыше - обработает и поменяет других детей, если надо. А если у ребенка спросили что-то что он не знает (или даже ему самому потребовались внешние данные), что делать? Один из моих подходов - пропихиваем в ребенка при создании класс-сервис, у которого есть поля с нужными данными (его трудно тянуть, иногда такие сервисы становятся сингликами) Ваш подход: -у ребёнка что-то спросили -он шлет событие -его обрабатывает родитель -родитель дергает геттер ребёнка и присваивает нужное значение Что-то подсказывает, что такая схема будет неудобной/ненадежной. Я правильно хоть суть понял? |
Класс-сервис усложнит только ребенка, и добавятся ещё события о том что ребенок, например, не нашел нужные данные, т.е. в него придется вкладывать логику и опять пойдут события аля "parentHelpMe.IdontKnowWhatToDo"
|
Цитата:
Давайте обсудим с примерчиками, может я чего-то не знаю ) |
| Часовой пояс GMT +4, время: 09:29. |
Copyright © 1999-2008 Flasher.ru. All rights reserved.
Работает на vBulletin®. Copyright ©2000 - 2026, Jelsoft Enterprises Ltd. Перевод: zCarot
Администрация сайта не несёт ответственности за любую предоставленную посетителями информацию. Подробнее см. Правила.