Обычная версия
Java форум JavaTalks
форум программистов

Поиск   Пользователи   Группы   Регистрация 
 Профиль   Личные сообщения 

 Вход 

Очистка коллекции
Список форумов
 ->  Коллекции (Java Collection Framework)


На страницу Пред.  1, 2 
Начать новую тему 
Предыдущая тема :: Следующая тема  
Автор Сообщение
Taky_ : 491
Бывалый

СообщениеАвг 13, 2011 15:43 
Ответить с цитатой
mpoSimba, я вас не совсем понял.
Когда я пишу:
Код:
List<SomeClass> list = new ArrayList<SomeClass>();
я имею возможность изменить реализацию на связанный список и поменять производительность программы например.
Принцип подстановки Лисков(в честь Барбары Лисков, которая в 70 еще язык CLU создала) гласит: Пусть q(x) является свойством, верным относительно объектов x некоторого типа T. Тогда q(y) также должно быть верным для объектов y типа S, где S является подтипом типа T. см. http://ru.wikipedia.org/wiki/Принцип_подстановки_Лисков

Пример неверного использования: если в метод который использует public E set(int index, E element) через List передать List, который вернет функция: Array.asList(...) или Collections.nCopies(int n, T o). Т.к. будет вызвана реализация из AbstractList и кинется исключение: UnsupportedOperationException.

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

Кажется так.
К началу Посмотреть профиль Отправить личное сообщение
Tricks`Ter : 224
Новичок

СообщениеАвг 13, 2011 15:49 
Ответить с цитатой
mpoSimba писал(а):
...
Верный контракт aList не утерян.


А можно чуть подробнее? Не понял, почему при первом варианте контракт теряется. Мы же потеряли только объявленный, а не фактический тип.
К началу Посмотреть профиль Отправить личное сообщение
mpoSimba : 124
Новичок

СообщениеАвг 13, 2011 16:37 
Ответить с цитатой
Taky_

Если вы НЕ ЗАВИСИТЕ от непосредственной реализации, то СЛЕДУЕТ инвертировать управление и передать создание самой реализации кому-либо ещё, а в конструкторе декоратора компонента требовать контракт List.

Код:

public SomeClass<T> {
    public SomeClass(List<T> list_);
}

//...
ArrayList<AnotherClass> aList = new ArrayList<AnotherClass>();
//do something with aList as the AraayList entity

SomeClass<AnotherClass> SomeClassObj = new SomeClass<AnotherClass>(aList);
//do something as the List entity

aList = null; //return to the Force


Смотрите. Читать правильно ООП код следует так:
SomeClass(List<T> list_);

Я, SomeClass, торжественно клянусь, что буду клиентом list_ и обязуюсь использовать только методы List. Я доверяю интерфейсу List. При этом поставщик list_ может держать ещё тысячу контрактов с другими клиентами. Если SomeClass попытается использовать метод не по контракту с List, компилятор привлечёт его к суду.

Принцип подстановки гласит, что никто не может "врать". Если я утверждаю, что я "подтип", то я автоматически "принимаю" контракт того, кому наследую, и обязуюсь его чтить и соблюдать.

UnsupportedOperationException -- это нарушение контракта. Вероятно, это Java Fail, связанный с отсутствием контракта типа C++ const.
Если бы был контракт, какой-нибудь final List, который не содержал бы операции set, то уже на этапе компиляции всё разрешилось бы, исключение не потребовалось бы. А в каком-нибудь языке без строгой типизации операция, вероятнее всего, просто тихо не сработала бы. Контракт автоматически изменён.



Tricks`Ter
Зачем нужна статическая типизация?
Ответив на этот вопрос, вы поймёте, что именно потеряли.
К началу Посмотреть профиль Отправить личное сообщение
mpoSimba : 124
Новичок

СообщениеАвг 13, 2011 17:05 
Ответить с цитатой
Я согласен, что то, о чём веду речь -- сильно теоретизированно. Университетского типа вопрос, который к практике имеет мало отношения.
Если работать в рамках концепции, поддерживаемых ООП, то проектирование затянется на тысячи человеко*часов. Для практики ужасная роскошь.

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

Если ваша программа инстанцирует ArrayList, значит она хочет произвольного доступа. Зачем кастовать в List? Это только лишает возможности работы с ArrayList.
Если ваша программа инстанцирует LinkedList, значит достаточно связанного списка. Зачем сжимать его до List?
Если вам действительно нужен только List, заверните ваш класс в контейнер, который даст вам реализацию и будет её менять в зависимости от нужд других кусков программы, которые могут захотеть LinkedList или ArrayList.
К началу Посмотреть профиль Отправить личное сообщение
Dagdamor : 406
Бывалый

СообщениеАвг 14, 2011 13:17 
Ответить с цитатой
Цитата:
Зачем кастовать в List? Это только лишает возможности работы с ArrayList.
Если ваша программа инстанцирует LinkedList, значит достаточно связанного списка. Зачем сжимать его до List?

У типа List все же есть оно преимущество - он пишется короче Very Happy

Хотя Джава - увы, не тот язык, в котором можно избежать бессмысленной писанины... как же мне в нем после PHP не хватает родной поддержки ассоциативных массивов (они же хеши)... $item["field"] куда красивее и быстрее, чем item.getField() или item.get("field"). После PHP и его легкости, все эти неизбежные интерфейсы, классы и дженерики - и все это только чтобы хранить десяток строк - выглядит как... не скажу что Sad
_________________
Java и трассировка лучей
К началу Посмотреть профиль Отправить личное сообщение
mpoSimba : 124
Новичок

СообщениеАвг 14, 2011 14:59 
Ответить с цитатой
Не помню, отмечал ли я это в теме PHP vs. Java, но сравнение Java и PHP по скорости разработки -- бессмысленно. Потому что из проекта перейти в конструирование в PHP практически всегда можно без "швов". В Java -- нет.
Нестрогая типизация, как показала практика, действительно ускоряет разработку. В то же время, в современном PHP есть возможность определять и требовать пользовательские контракты.
Если подойти к PHP с умом, то можно писать коды, которые легко переиспользовать, на порядок легче, чем C++ коды, легко модифицировать даже если внутренние контракты повреждаются, гораздо легче писать самоизменяющиеся коды (например самовосстанавливающиеся или самообновляемые) и т.д.

Только, глядя на тенденции в PHP, складывается впечатление, что он неизбежно скатится в "настоящий ООП-язык со строгой типизацией", потому что "средний менеджер проектов" полагает, что это "классно!".
К началу Посмотреть профиль Отправить личное сообщение
Dagdamor : 406
Бывалый

СообщениеАвг 14, 2011 16:56 
Ответить с цитатой
Строгая типизация - это полбеды, в конце концов, все новшества, те же типы в аргументах функции - всегда вещи опциональные, кто-то пишет по-новому, кто-то пишет legacy.
Но у Джавы еще столько подводных камней... например, я до сих пор не понимаю, почему в ней 5/2=2. Мне страшно подумать, сколько людей за все эти годы лишились работы из-за этой подлянки.
Или крайне странные приоритеты операций... например, побитовые операции с числами имеют низший приоритет, чем арифметические. Хотя во всех языках, что я знаю, все наоборот.
Вчера изучал компараторы - меня совершенно убил абзац про запрет на использование унарного минуса в компараторах... причина: -MININT = +MININT. Хоть смейся, хоть плачь...
_________________
Java и трассировка лучей
К началу Посмотреть профиль Отправить личное сообщение
Taky_ : 491
Бывалый

СообщениеАвг 15, 2011 11:58 
Ответить с цитатой
mpoSimba, спасибо за интересный ответ.

С LSV вроде бы разобрались. По поводу "никто не должен врать" очень доступноSmile
Цитата:
Если вы НЕ ЗАВИСИТЕ от непосредственной реализации, то СЛЕДУЕТ инвертировать управление и передать создание самой реализации кому-либо ещё, а в конструкторе декоратора компонента требовать контракт List.


Ну да, вы правы, в теории есть несколько средств реализации IOC. Тем не менее на практике это делать дорого. Иногда мне не надо даже фабрику плодить, но очень часто достаточно простого контракта List(а если уже о практике, то можно понянуть Map).
По поводу советую почитать http://java.sun.com/docs/books/effective/toc.html Refer to objects by their interfaces. Когда я пишу:
Код:
List<Some> l = new ArrayList<Some>();
я не хочу делать попусту фабрику, но я оставляю себе возможность сменить реализацию в одном месте.

Цитата:
Если ваша программа инстанцирует ArrayList, значит она хочет произвольного доступа. Зачем кастовать в List? Это только лишает возможности работы с ArrayList.
Если ваша программа инстанцирует LinkedList, значит достаточно связанного списка. Зачем сжимать его до List?
Если вам действительно нужен только List, заверните ваш класс в контейнер, который даст вам реализацию и будет её менять в зависимости от нужд других кусков программы, которые могут захотеть LinkedList или ArrayList.

Делать контейнер - дорого. Если логики у сущности не достаточно чтобы она была сущностью? Не надо делать ее тогда. Если программа использует List, значит ей достаточно List. Если она использует LinkedList, значит ей не достаточно List, ей надо что-то попикантнее. Если мы используем Vector, значит нам нужна линейная память с произвольным доступом и реботой в многопточной среде. А потом бах, рефакторинг и у каждого треда свой список, тогда можно поднять perfomance и заюзать ArrayList.
К началу Посмотреть профиль Отправить личное сообщение
mpoSimba : 124
Новичок

СообщениеАвг 15, 2011 17:13 
Ответить с цитатой
Taky_
Цитата:
По поводу "никто не должен врать" очень доступно

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

Цитата:
Тем не менее на практике это делать дорого.

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

Цитата:
я оставляю себе возможность

себе -- это ключевое слово.
При использовании невозможно сменить реализацию. То есть, вы подразумеваете, что это не будет нужно. Вы спроектировали компонент, но оставили себе возможность изменить что-то. Зачем? Если компонент уже спроектирован и выпущен?
Как-то концы с концами не сходятся.
К началу Посмотреть профиль Отправить личное сообщение
Taky_ : 491
Бывалый

СообщениеАвг 16, 2011 9:31 
Ответить с цитатой
Цитата:
себе -- это ключевое слово.
При использовании невозможно сменить реализацию. То есть, вы подразумеваете, что это не будет нужно. Вы спроектировали компонент, но оставили себе возможность изменить что-то. Зачем? Если компонент уже спроектирован и выпущен?
Как-то концы с концами не сходятся.

Это где-то в недрах моего компонента. В версии 2.0 я беру и меняю логику... в остальном коде я опираюсь на абстракции.
Когда же я пишу как вы рекомендуете:
Код:
ArrayList arrayList = new ArrayList();
я привязываюсь к реализации в коде. Когда я ссылаюсь как на интерфейс, то я оставляю возможность легко сменить реализацию в одном месте. А не в двух как минимум) Я заставляю человека, который будет работать с этим кодом, понимать, что я привязываюсь только к линейной структуре данных.
Код:
List arrayList = new ArrayList();

В идеале можно бы вынести это в IOC контейнер, или как минимум сделать фабричный метод:
Код:
List arrayList = createList();
private List createList(){ return new ArrayList(); }

Далее компонент с методом createList() выделяем в класс и поднимаем уровень абсракциидо класса. Класс делаем как плагин. Получаем еще более мощный дизайн.

Но не всегда такую гибкость иметь целесообразно. На каждый чих создавать по классу или как минимум по методу - не правильно.
Поэтому ссылка на интерфейс, а не на класс в момент создания мне кажется компромисом:
Код:
List arrayList = new ArrayList();


P.S. Где вы набрались идей по поводу потеряного контракта? Можно и мне почитать? Или сами дошли?
К началу Посмотреть профиль Отправить личное сообщение
mpoSimba : 124
Новичок

СообщениеАвг 16, 2011 11:39 
Ответить с цитатой
Относительно версий.
Если вы закрыли компонент и выпустили как готовый, то версия 2.0 -- это логическое противоречие тому, что компонент выпущен.
Если вы знали, что компонент будет по различным причинам изменяться, тогда
Цитата:
поднимаем уровень абсракциидо класса. Класс делаем как плагин.

Проектное решение отражает возможность изменения внутреннего "неготового" компонента, отделяя его от клиента слоем.

Цитата:
На каждый чих создавать по классу или как минимум по методу - не правильно.

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

Цитата:
Поэтому ссылка на интерфейс, а не на класс в момент создания мне кажется компромисом:

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

Приходите вы в магазин и спрашиваете: "Хлеб свежий? -- Только что привезли", -- отвечает продавщица.
Вы не получили ответа на свой вопрос! Будьте внимательны. Хлеб могли привезти и чёрствым. Но... Любой "вменяемый" человек понимает, что хлеб свежий, делая логический доверительный скачок, что хлеб всегда привозят свежим. Но это не укладывается в рамки "формальной логики", а для человека нормально.

Код:
List<SomeClass> list = new ArrayList<SomeClass>();

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

Цитата:
сами дошли?

Полезно думать самому, вам тоже советую.

http://download.oracle.com/javase/6/docs/api/java/util/ArrayList.html
http://download.oracle.com/javase/6/docs/api/java/util/List.html

Найдите отличия этих двух интерфейсов. Поймёте, какие именно части контракта вы потеряли.

Ожидаю разного рода возражения на основании рефлекции.
Упреждаю.
Рефлекция сама по себе уже связана с нарушением контракта и очень-очень опасны.
К началу Посмотреть профиль Отправить личное сообщение
Taky_ : 491
Бывалый

СообщениеАвг 16, 2011 12:05 
Ответить с цитатой
Цитата:
Полезно думать самому, вам тоже советую.

? Мои рассуждения основаны на опыте, произведенном рефакторинге + нашел из подтверждение в мыслях одного из ведущих экпертов по Java в мире.

Цитата:
Ожидаю разного рода возражения на основании рефлекции.
Глупое ожидание. Мы с вами вроде бы про ООП и нормальные подходы говорим.
Повторю еще раз, если мне достаточно в данном участке кода List, то лучше юзать List. Меньше знаешь, крепче спишь. Меньше связаность, выше ортогональность, легче менять! А изменять придется, не стойкость требований - одна из самых важных проблем в разработке ПО.

Скатились до какого-то холивара. Ну что ж теперь жалко времени.
К началу Посмотреть профиль Отправить личное сообщение
 
Начать новую тему  Ответить на тему
Страница 2 из 2
На страницу Пред.  1, 2
Список форумов
 -> Коллекции (Java Collection Framework)


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


Java and all Java-related trademarks and logos are trademarks or registered trademarks of Oracle Corporation in the United States and other countries.
Это сайт не относится к фирме Oracle Corporation и не поддерживается ею.

© 2006-2010 www.javatalks.ru: форум java программистов
Используется скрипт phpBB © 2001, 2010 phpBB Group

Хостинг от bizname.ru