Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Прочее";
Текущий архив: 2007.12.23;
Скачать: [xml.tar.bz2];

Вниз

Похоливарим еще? (java, checked exceptions)   Найти похожие ветки 

 
Юрий Зотов ©   (2007-11-16 07:05) [0]

Итак, известно, что ежели метод может выбросить исключение класса RuntimeException (что по дефолту предполагается для всех методов), то компилятор не потребует ни throws в заголовке метода, ни обязательного try-catch внутри него. Обрабатывать такое исключение внутри метода, или пропустить его выше - это решение отдается на откуп программисту.

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

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

Как уже отмечалось, та же стратегия принята и в джаве, но только для исключений, принадлежащих семейству RuntimeException. Для прочих же исключений дело обстоит несколько иначе. Мы не можем просто так написать следующее:
public void method() {
 ...
 throw new Exception("Ошибка"); // Возбуждение исключения
 ...
}

потому что компилятор тут же потребует одно из двух:
- либо чтобы возбужденное нами же исключение было обработано тут же внутри метода;
- либо чтобы в заголовок метода была добавлена фраза throws Exception (которая информирует, что этот метод может возбуждать исключения семейства Exception).

Рассмотрим оба варианта подробнее.

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

Что ж, тогда у меня остается второй, вполне логичный вариант - добавить в заголовок метода фраза throws Exception, тем самым задекларировав, что метод может выбрасывать исключения. Если такой метод вызвать из другого метода, то теперь уже для вызывающего метода компилятор потребует то же самое - либо обрабатывай исключение по месту, либо декларируй его в заголовке - и т. д., по всей цепочке вызовов.

Вариант логичный. Но неудобный. Представим себе сторонний класс (или интерфейс), в котором объявлен какой-то метод. Я в своем классе этот метод перекрываю (или реализую). Изменить объявление метода, добавив туда throws, конечно, нельзя. Поэтому, если в моем коде мне по каким то причинам нужно возбудить исключение, то я обязан тут же его и обработать, а передать его наверх у меня нет никакой возможности, хотя именно это мне и нужно! И тогда весь смысл собственноручного возбуждения исключения пропадает полностью!

Теперь вопрос - а на фига так сделано? Ну почему было не оставить нормальную концепцию обработки исключений - как RuntimeException, как в Delphi? Зачем потребовался такой выпендреж? Ради строгости языка? Чтобы подстраховать неумелого программера, заодно подрезав и всех остальных? То есть - мыши плакали, кололись, но продолжали есть кактусы?

Или я чего-то не понимаю?


 
Канадец   (2007-11-16 08:03) [1]

Понятно, что вариант "сам выбросил, сам поймал" это не то, что имели ввиду имплементаторы данной концепции. Т.е. остаётся второй вариант...

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


> Представим себе сторонний класс (или интерфейс), в котором
> объявлен какой-то метод. Я в своем классе этот метод перекрываю
> (или реализую). Изменить объявление метода, добавив туда
> throws, конечно, нельзя. Поэтому, если в моем коде мне по
> каким то причинам нужно возбудить исключение, то я обязан
> тут же его и обработать, а передать его наверх у меня нет
> никакой возможности, хотя именно это мне и нужно! И тогда
> весь смысл собственноручного возбуждения исключения пропадает
> полностью!


А теперь посмотрим на эту проблему с другой стороны.
Пользователь стороннего класса (или интерфеса) при вызове данного метода должен чётко предствлять, что в произойдёт в результате. Результатов возможно два (краш приложения рассматривать не будем, оставим это китайцам:) ):  метод либо выполнится, либо в результате работы метода возникнет исключение. С первым вариантом всё хорошо. А вот со вторым... Хорошо, когда мы имеем дело с задокументированной .NET Framework библиотекой. Пошёл себе на MSDN, а там this method throws the following exceptions. Всё чётко и понятно. А что делать с нерадивыми товарищами, которые эксепшионы плюют, а упоминать про них в документации забывают?

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

Что хуже в данном случае: гибкость переопределения виртуальных методов или ожидаемое и прогнозируемое поведение этих методов, вопрос IMHO спорный.


 
Kolan ©   (2007-11-16 08:46) [2]


> а упоминать про них в документации забывают?

Смотреть в код. Это вообще не аргумент имхо, если нормальный производитель класса, то документация будет...


 
Юрий Зотов ©   (2007-11-16 08:49) [3]

> Канадец   (16.11.07 08:03) [1]

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

Вот Вы говорите: "А что делать с нерадивыми товарищами, которые эксепшионы плюют, а упоминать про них в документации забывают"?

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

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

А знаете, что тогда делает этот товаришч? А он берет - и выбрасывает задокументировнный эксепшн. Но с совершенно другим смыслом. И этот новый смысл тоже не документирует. А компилер он обманул.

И что получается? Если бы этот товаришч не был вынужден пороть такую фигню, а имел возможность выкидывать произвольные исключения, то по смыслу своей ошибки он бы выбросил исключение наиболее подходящего класса. Ну, например, ConvertException ("Ошибка преобразования Васи в Петю"). И для Вас, как для его пользователя, все было бы информативно и понятно.

А поскольку товаришч вынужден-таки фигню пороть, то Вы получаете что-то типа ClassNotFoundException("Ошибка преобразования Васи в Петю"). И начинаете судорожно соображать, какое же отношения имеет ненайденный класс к преобразованию Васи в Петю? Лезете в документацию - да, такой эксепшн есть, все нормально. Но при чем тут Вася с Петей - загадка.

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


 
Однокамушкин   (2007-11-16 09:12) [4]


> Канадец   (16.11.07 08:03) [1]
> Дальше больше.... допустим идеальный вариант. Есть некий,
>  хорошо задокуменированый класс с виртуальным методом, который
> чётко в документации указывает исключения какого рода он
> может порадить. Дальше следуя Вашему второму варианту появляется
> некто, кто пишет наследника, переопределяет данный метод
> и плюёт исключение, которое нигде не упоминается в описании
> базового класса. Вопрос: я, как пользователь базового класса,
>  какие исключения должен ожидать от этого метода?

Нехорошо, конечно... Но, с другой стороны: есть у меня, например, базовый класс TStream для потока... От него порождены TFileStream, TResourceStream и TSocketStream, которые, понятно, работают совершенно с разными источниками данных и поэтому сталкиваются с совершенно разными ошибками... Ну и что, методы базового класса должны учитывать все возможные исключения, что ли? А если появится новый источник данных с новыми типом исключений? Или надо предусмотреть одно исключение на все случаи жизни? Но тогда обработка этих исключений будет сильно затруднена... В общем, я согласен с Юрием


 
Bishop   (2007-11-16 09:25) [5]

Юрий Зотов ©   (16.11.07 07:05)

В головах она разруха то, а не в клозетах. Зачем на клозет сетуете по чем зря?


 
Юрий Зотов ©   (2007-11-16 09:28) [6]

> Bishop   (16.11.07 09:25) [5]

Спасибо за очень полезное, информативное и хорошо обоснованное мнение.


 
mephasm   (2007-11-16 09:40) [7]


> Представим себе сторонний класс (или интерфейс), в котором
> объявлен какой-то метод. Я в своем классе этот метод перекрываю
> (или реализую). Изменить объявление метода, добавив туда
> throws, конечно, нельзя. Поэтому, если в моем коде мне по
> каким то причинам нужно возбудить исключение, то я обязан
> тут же его и обработать, а передать его наверх у меня нет
> никакой возможности, хотя именно это мне и нужно! И тогда
> весь смысл собственноручного возбуждения исключения пропадает
> полностью!


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


 
mephasm   (2007-11-16 09:48) [8]

Впрочем, даже без instanceof вы можете перехватывать исключение ровно вашего типа.


 
Юрий Зотов ©   (2007-11-16 09:53) [9]

> mephasm   (16.11.07 09:40) [7]

> В этом методе, как правило, объявлен выброс исключения некоего
> базового типа.


В самом деле? А если не объявлен?
"Как правило" - это, конечно, сказано сильно. Но только сказано.

> Если вам нужно выбросить свое исключение, вы наследуете его

А если мне не нужно своего исключения? Если вполне устраивает уже имеющееся. И плодить сущности без необходимости тоже ни к чему?

========================

Более сильные и разумные аргументы имеются, господин Бишоп?


 
Anatoly Podgoretsky ©   (2007-11-16 09:55) [10]

> Юрий Зотов  (16.11.2007 09:53:09)  [9]

В корзину, но на всех идиотов корзин не хватит.


 
mephasm   (2007-11-16 10:00) [11]

Юрий Зотов ©   (16.11.07 09:53) [9]

Простите, но вы сокрушались по поводу того, что у вас нет возможности передать ваше исключение на верх. Она у вас есть.
Если вы ее не видите, то вам остается только горько плакать.


 
Юрий Зотов ©   (2007-11-16 10:09) [12]

> mephasm   (16.11.07 10:00) [11]

А можно без болтологии? И без "как правило". И без голословных заявлений?

Вы говорите, она у меня есть - ну так или покажите ее, или помолчите.


 
Romkin ©   (2007-11-16 10:13) [13]

Стоп. Разве нельзя действительно объявить потомка и выбрасывать его?
Или выбросить потомка RuntimeException?


 
mephasm   (2007-11-16 10:31) [14]

Юрий Зотов ©   (16.11.07 10:09) [12]
Пожалуйста.

Посмотрите, как это реализовано, к примеру, в JAXP. JAXP, это интерфейс, который реализуют различные XML парсеры.
Метод parse SAX парсера выбрасывает SAXException.
Это может быть SAXParseExcepiton, в случае когда анализируемый XML не валиден и какой-либо другой эксепшн, связанный например с неправильной конфигурацией парсера (покопайтесь в исходниках парсера xerces, они открыты).
Если мы только проверяем XML на валидность, мы можем явно написать
            try
            {
             parser.parse(inputXML, handler);
            }
            catch(SAXParseException e)
            {
             // report error
            }

Все остальные исключения перебрасываются дальше.
И это будет работать. Не понимаю в чем вы видите проблему.


 
Юрий Зотов ©   (2007-11-16 10:35) [15]

> Romkin ©   (16.11.07 10:13) [13]

Приведу пример, чтоб все стало ясно. Есть метод:
public void method()  {
...
}

Тут не задекларировано ничего, поэтому при перекрытии этого метода можно выбросить только RuntimeException (или потомка RuntimeException). Допустим, перекрытый метод работает с файлом - то есть, возможно IOException. Его и надо выбрасывать - но нельзя. Все, что тут можно сделать, это переопределить исключение:

public void method()  {
 try {
   ...
 } catch (IOException e) {
  throw new MyRuntimeException(...)
 }
}

Согласись, что подмена исключения - это кривовато как-то. За уши притянуто - лишь бы только обойти ограничение компилятора.

Второй вариант. Пусть перекрываемый метод что-то декларирует:
public void method() throws SomeException {
 ...
}

В этом случае можно выбросить SomeException (либо его потомка) или RuntimeException (либо его потомка). А у меня, как уже говорилось, возникает IOException - и я снова вынужден подменять исключение. Снова кривизна, снова притягивание за уши.

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


 
Юрий Зотов ©   (2007-11-16 10:40) [16]

> mephasm   (16.11.07 10:31) [14]

> Не понимаю в чем вы видите проблему.

Напишите потомка парсера, перекройте его метод parse и попробуйте выбросить из него... ну, к примеру, SQLException. Увидите.


 
Сусл ©   (2007-11-16 10:41) [17]


>  [13] Romkin ©   (16.11.07 10:13)
> Стоп. Разве нельзя действительно объявить потомка и выбрасывать
> его?
> Или выбросить потомка RuntimeException?

+1
присоединяюсь к вопросу.

------------
2ЮЗ. По теме.
Я думаю, что то, как сделано в java очень хорошо. Мне этого очень не хватает в delphi.

Почему?
1. throws - это инструмент документирования. По моему мнению throws ничем не отличается по вкладу в документацию от списка параметров, скажем.
2. Это выводит на чистую воду ленивых кодеров. Сравни 2 сценария. Ты делаешь стат. тестирование (просматриваешь код) за Ваней, и выщишь примерно ткой вызов (синтаксис точный не помню):

 
SomeMethodCodedByYoryZotov();


Твоя мысль: а все ли Ваня учел? Где обработка исключений? Здесь, выше? Вот же ведь лапух, забыл. Ага ну давай теперь пользователю выводить сообщение о том, что в каком-то там классе хибернейта, что-то там глюкнолось. Ан нет, выше он обработал, молодец. Стоп! А где же я остановился? О! Я остановился на мысле о пиве! Пора домой!

try {
  f();
}
catch() {
обработка
}


Смотришь на такой код и видишь (вернее точно знаешь!) сразу, что Ваня не может не обработать искючение!

Резюм - контроль за кодом выше при существовании сабжевой фичи.


 
Romkin ©   (2007-11-16 10:47) [18]

Юрий Зотов ©   (16.11.07 10:35) [15] Угу. Идею понял.
Но подозреваю, что когда пишешь конкретного предка, ты все-таки предполагаешь, что будет, и пишешь нужный тип.
То есть, тут явно пытаются заставить тебя делать так, чтобы твоя иерархия классов возбуждала исключения только твоего типа, если, конечно, ты не предусмотрел орлиным взором иное.
Вопрос в том, почему, когда перекрываешь метод, нельзя определить исключения?


 
Romkin ©   (2007-11-16 10:47) [19]


> Вопрос в том, почему, когда перекрываешь метод, нельзя определить
> исключения?

Мда. Глупый вопрос...


 
Romkin ©   (2007-11-16 10:50) [20]


> Смотришь на такой код и видишь (вернее точно знаешь!) сразу,
>  что Ваня не может не обработать искючение!

Угу. Смотришь код Васи, и видишь обработку вроде такой:
try {
 f();
}
catch() {}

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


 
Сусл ©   (2007-11-16 10:54) [21]

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

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

Есть еще агрегация. Да мало ли чего. Вот я тебе очень советую почитать GoF "Паттерны проектирования". Я знаю, что многие относятся к паттернам отрицательно - типа я и сам все знаю, и вообще паттерны - это мантра, а мы сами думать умеем. В чем-то я даже могу согласиться с таким мнением, но далеко не во всем. Паттерны нужно знать, чтобы мыслить шире, а не только наследованием.

Если вернуться к обозначенной тобой проблеме - нельзя выкинуть исключение, относящиеся к SQL, при переопределении метода, то посмотри, может не так хороша твоя архитектура, может не нужно засовывать функционал, связанный с SQL в наследников? Может сделать отдельный класс, который будет использовать твой базовый? Может так гибче?


 
Сусл ©   (2007-11-16 10:55) [22]


>  [20] Romkin ©   (16.11.07 10:50)
> Что-то мне все больше кажется, что java рассчитывает на
> программистов, мягко сказать, крайне невысокой квалификации
> :(


Возможно, Роман, ты и прав. И в этом нет ничего постыдного для программиста java. Задача любого программиста писать быстро, качественно и выдавать решения, соответствующие задачи. И любые методы, которые этому способствуют приемлемы.


 
Юрий Зотов ©   (2007-11-16 10:57) [23]

> Romkin ©   (16.11.07 10:47) [18]

> когда пишешь конкретного предка, ты все-таки предполагаешь,
> что будет, и пишешь нужный тип.

Однокамушкин приводил пример. Пишу я Stream. Потомков у него может быть вагон и каждый работает со своим хранилищем данных.
FileStream - это IOException
BlobStream - это SQLException
SocketStream - это какой-нибудь ConnectException.

И т.д. Непредсказуемо. И что мне тогда писать в своем стриме-предке? Остается только одно - общий Exception, больше делать нечего. Конкретика исчезла.

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


 
Сусл ©   (2007-11-16 11:00) [24]


> [23] Юрий Зотов ©   (16.11.07 10:57)
> > Romkin ©   (16.11.07 10:47) [18]
>
> > когда пишешь конкретного предка, ты все-таки предполагаешь,
> > что будет, и пишешь нужный тип.
>
> Однокамушкин приводил пример. Пишу я Stream. Потомков у
> него может быть вагон и каждый работает со своим хранилищем
> данных.
> FileStream - это IOException
> BlobStream - это SQLException
> SocketStream - это какой-нибудь ConnectException.
>
> И т.д. Непредсказуемо. И что мне тогда писать в своем стриме-предке?
> Остается только одно - общий Exception, больше делать нечего.
> Конкретика исчезла.
>
> А если б было можно, я бы не писал ничего. И пусть потомки
> возбуждают, что им угодно.

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


 
Romkin ©   (2007-11-16 11:01) [25]


> Возможно, Роман, ты и прав. И в этом нет ничего постыдного
> для программиста java. Задача любого программиста писать
> быстро, качественно и выдавать решения, соответствующие
> задачи. И любые методы, которые этому способствуют приемлемы.
>

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


 
Игорь Шевченко ©   (2007-11-16 11:01) [26]


> Однокамушкин приводил пример. Пишу я Stream. Потомков у
> него может быть вагон и каждый работает со своим хранилищем
> данных.
> FileStream - это IOException
> BlobStream - это SQLException
> SocketStream - это какой-нибудь ConnectException.


Эта..я Java плохо знаю, в связи с чем вопрос - а что, в throws можно объявлять только явные типы исключений, то есть, общего предка типа MyStreamException объявить нельзя ? Или исключения не наследуются ?


 
Сусл ©   (2007-11-16 11:02) [27]


> То есть уровень вхождения в язык довольно низок, а вот чтобы
> написать нечто существенное...

да так в любом языке :)


 
Romkin ©   (2007-11-16 11:02) [28]


> Э... а как прикажешь вести себя классу, который использует
> конкретных потомков Stream через интерфейс Stream? Т.е.
> путь живет в состоянии неизвестности - какое там ичключение
> может быть, что ему делать?

А что ты делаешь в Delphi? Я - обычно ничего :)


 
Сусл ©   (2007-11-16 11:02) [29]


>
> Эта..я Java плохо знаю, в связи с чем вопрос - а что, в
> throws можно объявлять только явные типы исключений, то
> есть, общего предка типа MyStreamException объявить нельзя
> ? Или исключения не наследуются ?

я тоже плохо знаю, но предка обявить можно :)


 
Сусл ©   (2007-11-16 11:02) [30]


> А что ты делаешь в Delphi? Я - обычно ничего :)

Ну это ты :)


 
Romkin ©   (2007-11-16 11:08) [31]


> Ну это ты :)

А ты перехватываешь? Я обычно пользователю показываю :) Если в потомке Stream случилось что-то - это, скорее всего, требует вмешательства извне.
Вопрос в том, что и эксепшен я не объявляю... Нафига?
Тут ведь идея какая: либо ты знаешь, что тебе нужно перехватить исключение, либо нет. Если знаешь - перехватываешь, если нет - все все равно будет работать.


 
Romkin ©   (2007-11-16 11:12) [32]

Игорь Шевченко ©   (16.11.07 11:01) [26]

> Эта..я Java плохо знаю, в связи с чем вопрос - а что, в
> throws можно объявлять только явные типы исключений, то
> есть, общего предка типа MyStreamException объявить нельзя
> ? Или исключения не наследуются ?

Можно. И потомок будет вынужден перехватывать, например, IOException и возбуждать вместо него потомка MyStreamException. Я об этом уже замечание написал, обрати внимание.
Вопрос еще в том, что надо не упустить, и предусмотреть в предке этот MyStreamException, а это требует хорошего планирования, можно сказать, сразу всей иерархии.
Так что на мой взгляд, такой подход действительно делает построение иерархических структур в java более сложным делом, чем в Delphi, например.
И Сусл в [21] правильно заметил, что, повидимому, должен быть другой подход (подозреваю, что через интерфейсы).


 
Игорь Шевченко ©   (2007-11-16 11:14) [33]

Romkin ©   (16.11.07 11:12) [32]


> Можно. И потомок будет вынужден перехватывать, например,
>  IOException и возбуждать вместо него потомка MyStreamException


Это как-то противоречит принципам ООП о скрытии деталей реализации ?


 
Игорь Шевченко ©   (2007-11-16 11:20) [34]

Кстати, об ООП - не могу удержаться, чтобы не привести цитату:

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

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

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


 
Сусл ©   (2007-11-16 11:22) [35]


> [34] Игорь Шевченко ©   (16.11.07 11:20)

+1


 
@!!ex ©   (2007-11-16 11:23) [36]

> [34] Игорь Шевченко ©   (16.11.07 11:20)

+1

Однако примеры Юрия не подразумевают сложную иерархию.
Тот же TStream имеет всего пару уровней наследования, однако проблему это не решает.


 
Игорь Шевченко ©   (2007-11-16 11:27) [37]

@!!ex ©   (16.11.07 11:23) [36]


> Однако примеры Юрия не подразумевают сложную иерархию.
> Тот же TStream имеет всего пару уровней наследования, однако
> проблему это не решает.


А скажи мне пожалуйста, за каким бесом пользователю Stream надо знать, что произошло исключение связанное с поведением конкретного наследника Stream ?
Полиморфизм в чистом виде, что ли ? :)


 
mephasm   (2007-11-16 12:10) [38]

Про nested exceptions слышали?

public void startElement (String name, AttributeList attrs)
throws SAXException {
try
{
 if (name.equals("SCHEDULE"))
 {
  this.ParseStartSchedule(attrs);
  return;
 }

 return;
}
catch (IOException e)
{
 throw new SAXException("I/O error: " + e.toString(), e);
}
catch (ScheduleParseException e)
{
 throw new SAXException("ScheduleParseError" + e.toString(), e);
}
}


 
mephasm   (2007-11-16 12:11) [39]

mephasm   (16.11.07 12:10) [38]

Это к
Юрий Зотов ©   (16.11.07 10:40) [16]


 
mephasm   (2007-11-16 12:14) [40]

отлов соответственно такой
catch (SAXException e)
{
 //...
}
catch (IOException e)
{
 //...
}



Страницы: 1 2 3 4 5 6 вся ветка

Форум: "Прочее";
Текущий архив: 2007.12.23;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.61 MB
Время: 0.039 c
2-1196144972
Мистик
2007-11-27 09:29
2007.12.23
Сохранить аттач с руским именем из idmessage


6-1176222645
wolchonok29
2007-04-10 20:30
2007.12.23
Проблема с потоками


15-1195944028
Суслик
2007-11-25 01:40
2007.12.23
Некие новости о Delphi


15-1195572022
Kerk
2007-11-20 18:20
2007.12.23
Телефон чтоль порекомендуйте


1-1191594497
Cobalt
2007-10-05 18:28
2007.12.23
У кого-нить есть заголовки функций





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский