LINUX.ORG.RU

java, возврат а-ля const значения

 


0

3

Итак, есть у меня класс, пусть будет Data, содержащий в себе одним из полей самопальное Tree<Object>. Иногда есть необходимость посмотреть снаружи ентое самое дерево целиком, при этом запретив изменение как его самого, так и его элементов. Поменять поле на final - не решение, ибо дерево таки меняется другими методами. Поскольку никаких возвратов const у нас языком не предусмотрено, я вижу только варианты:

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

- возвращать копию всего дерева - ну вы понели(с).

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

используй immutable структуры данных

maxcom ★★★★★ ()

Поменять поле на final - не решение, ибо дерево таки меняется другими методами.

можно вопрос? а если у меня есть объект A со слотом B, в котором есть мутабельный слот C, и есть где-то метод, принимающую final A, я разве не могу в ней написать

A.B.C = что-нибудь
?

pseudo-cat ★★★ ()
Ответ на: комментарий от maxcom

было бы это так просто... Оне там в большинстве вполне так себе mutable, обвешанные листенерами. Да и на каждый чих получать полную копию объекта со всеми нижележащими - ява и так память как не в себя жрет.

arkhnchul ★★ ()

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

Deleted ()
Ответ на: комментарий от pseudo-cat

малость не понял вопроса. Но если моя интерпретация верна, и у нас есть нечто типа такого:

public class Foo{
public final AType A=new AType();
}
......
public class AType{
public Bar B=new Bar();
}

public class Bar{
public Integer C=20;
}

то да, new Foo().A.B.C=10 проканает. Нельза написать new Foo().A=new Atype(), ибо A - final и на данном этапе уже инициализировано, т.е. само по себе это поле (читай «ссылку на объект А») менять нельзя, но что там происходит внутрях А - проблемы А.

arkhnchul ★★ ()
Последнее исправление: arkhnchul (всего исправлений: 1)
Ответ на: комментарий от arkhnchul

да, я примерно об этом, просто фраза

ибо дерево таки меняется другими методами

неоднозначна - то ли ты имеешь ввиду, что тебе нужно именно мутабельное дерево в программе и ты хочешь его сделать полностью имутабельным в определенном месте, то ли говоришь о том, что final не спасет от мутабельности внутренней структуры дерева

pseudo-cat ★★★ ()
Ответ на: комментарий от Deleted

совсем нет? а если сделать абстрактное дерево тип с protected сеттерами и наследоваться от него с мутабельными public методами только там, где нужно его изменить, а в остальных местах downcast до псевдо-имутабельного?

pseudo-cat ★★★ ()
Последнее исправление: pseudo-cat (всего исправлений: 1)
Ответ на: комментарий от pseudo-cat

то ли ты имеешь ввиду, что тебе нужно именно мутабельное дерево в программе и ты хочешь его сделать полностью имутабельным в определенном месте, то ли говоришь о том, что final не спасет от мутабельности внутренней структуры дерева

я имею в виду, что у самого вот этого Data, в котором лежит экземпляр(ы) Tree, имеются методы типа addSomeLeaf(блабла критерии), modifyLeaf(еще чето), и вся полезная работа подразумевается с ними, но в паре мест внешнего по отношению к Data кода гораздо проще получить read-only экземпляр всего нужного (под)дерева, чем мудохаться с сими методами.

arkhnchul ★★ ()
Ответ на: комментарий от pseudo-cat

а как это решит проблему «внезапного» для клиентского кода изменения дерева?

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

все методы клиентского кода будут принимать аргумент downcast-ого типа? По отношению к клиентскому коду, другому наймспейсу, мутабельный тип будет private.

pseudo-cat ★★★ ()

Клиенту стопудово нужно отдавать копию. Других вариантов нет.

anonymous ()
Ответ на: комментарий от pseudo-cat

ты помешан на типах и их кастованию, проблема не там

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

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

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

pseudo-cat ★★★ ()

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

anonymous ()

Иногда есть необходимость посмотреть снаружи ентое самое дерево целиком

Вот тут тонкий момент, я называю его «правилом гопника». Надо всегда спрашивать у клиента (а точнее у самого себя): «А с какой целью интересуешься»? Действительно ли нужно отдавать клиенту всё дерево в первозданном виде? Ведь он как-то будет его просматривать или обрабатывать чтобы получить какие-то сведения. Какие именно сведения? Может попробовать сделать вместо простого getter'а какой-то другой более осмысленный метод, который вернёт клиенту не тупо дерево, а именно то, что ему (клиенту) на самом деле требуется.

CARS ★★★★ ()

у вас тут в проектировании проблема, по всей видимости. Зачем это дерево нужно еще где-то в другом месте?

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

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

«А с какой целью интересуешься»?

самое простое и очевидное - UI, всякие treeView-ы. Еще пригоршня функций, так или иначе анализирующих готовое (под)дерево.

Может попробовать сделать вместо простого getter'а какой-то другой более осмысленный метод, который вернёт клиенту не тупо дерево, а именно то, что ему (клиенту) на самом деле требуется

а нафига мне тогда «клиент», если все «самому» считать?)

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

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

если «клиенту» сего хозяйства прям нужна копия, то пусть дергает .copy() и готовит с сотню мегабайт памяти.

arkhnchul ★★ ()

Используй нормальный язык. С++, например.

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

Используй нормальный язык. С++, например.

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

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

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

А ты пробовал? С плюсами дружить надо. А те кто воюют как раз часто воюют и с const. Так что ты можешь смело записывать их в быдлокодеры и игнорить

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

ой, а можно решение данной проблемы на плюсах? желательно с const-ами))

anonymous ()

Как уже сказали - поле, в котором хранится мутабельный объект делаешь private, а для клиента создаешь геттер, который на основе мутабельного объекта создает immutable-версию этого Tree и возвращает копию.

kovrik ★★★★★ ()

Но лучше переделай логику.

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

А ты пробовал? С плюсами дружить надо.

я как-то не особо дружу. Всегда было лень разгребать, где там всякие ::, ->, &* итд превращаются в элегантные шорты (с этой стороны для меня мечта идиота - лисп, где всего синтаксиса - левая и правая скобки)), в каком там порядке чего где в .h и .cpp, всякие #IFDEF, лазание в кучу -I и -l компилятора и линкера етц. На уровне «написать числодробильный кусок шоп быстро было» меня хватает, но логику на плюсах писать - увольте, это не ко мне. .

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

который на основе мутабельного объекта создает immutable-версию этого Tree и возвращает копию.

затык в «возвращает копию». Писал уже - жирно получится кажный раз выдавать лишние 50-100 мегабайт только для того, чтобы их еще раз прочитать.

arkhnchul ★★ ()

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

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

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

Legioner ★★★★★ ()
Ответ на: комментарий от pseudo-cat

именно помешан, ты своими костылями от мутабельности не уйдешь, ты ее даже сам декларируешь только не понимаешь что это яма в кою ты попадешь 8)

Deleted ()
Ответ на: комментарий от Legioner

а нижележащие не копировать? они что общими останутся?)

pseudo-cat ★★★ ()
Ответ на: комментарий от Legioner

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

???

если ты ссылаешься только от папы к детям.

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

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

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

pseudo-cat ★★★ ()

А почему:

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

не подходит? Что под перетрахиванием подразумевается? ты везде не абстрактные классы задавал что-ли?

kovrik ★★★★★ ()
Ответ на: комментарий от pseudo-cat

Ты сказал невозможно, я решил опровергнуть!

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

Deleted ()
Ответ на: комментарий от Legioner
type A {
slot value of int; 
slot left of A; 
slot right of A;
}

a = new A(1; new A(2; new A(3; null; null); null); null)

b = new A(1; a.left.left); null)
b.left.value <- 0

a.left.left.value == b.left.value == true

в смысле иммутабельные?

pseudo-cat ★★★ ()
Ответ на: комментарий от Deleted

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

ясен хрен, разве не это нужно ТСу?

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

так вот перечитая про что я писал 8)

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

Deleted ()
Ответ на: комментарий от pseudo-cat

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

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

у нод дерева кроме child-ов есть еще такое private Object nodeData. Вот, к примеру, будет у меня unmodifableTree, где changeData() выбросит UnsupportedOperationException. Но если я прочитаю getNodeData(), где лежит какойнить ArrayList (в клинических случаях там еще одно самостоятельное Tree), то вполне смогу с ним делать чохошь. Т.е. эту самую ноддату тоже или оборачивать, или отдавать копию.

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

Думаю, что имелось в виду возвращение из метода const MyTree & или там shared_ptr<const MyTree>.

anonymous ()
Ответ на: комментарий от Deleted

извечный спор про мутабельность/немутабельность данных? Ну так-то да, я чаще буду за имутабельность

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

запретив изменение как его самого, так и его элементов

ок, приводить к типу с закрытыми сеттерами с помощью метода, который выставляет флаг отключения сеттеров - типо synchronize

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

извечный спор про мутабельность/немутабельность данных? Ну так-то да, я чаще буду за имутабельность

тебя в очередной раз понесло?

ок, приводить к типу с закрытыми сеттерами с помощью метода, который выставляет флаг отключения сеттеров - типо synchronize

что не решит указанной выше проблемы 8)

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

тебя в очередной раз понесло?

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

что не решит указанной выше проблемы 8)

а вот и решит

pseudo-cat ★★★ ()
Ответ на: комментарий от anonymous

Кстати, а есть еще какие-нибудь языки, кроме C, C++ и D с такой же развитой поддержкой констант?

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

Какой проблемы?

class Data
{
public:

    // ...

    shared_ptr<const Tree<Object>> GetTree() const
    {
        return tree;
    }

private:
    shared_ptr<const Tree<Object>> tree;
};

anonymous ()
Ответ на: комментарий от pseudo-cat

неизменяемый «вообще» объект никому нафиг ненужен 8)

Deleted ()
Ответ на: комментарий от anonymous

Если сами хотим менять, то поле объявляем так:

shared_ptr<Tree<Object>> tree;

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