Niemutowalna torba

0

Cześć,

wyobrażam sobie klasę Bag, która zwiera jakieś elementy (nie da się sprawdzić jakie) i na której mogę zawołać metodę .take(3). W wyniku chciałbym dostać trzy losowe elementy z mojej torby + nowy obiekt Bag z aktualnym stanem. Jak najlepiej zaprojektować takie API? Czy w ogóle jest sens, żeby ta klasa były niemutowalna?

2

Czy w ogóle jest sens, żeby ta klasa były niemutowalna?

Nie rozumiem pytania. Jeśli potrzebujesz coś takiego, to takie coś napisz :) Przecież sensowność wynika z potrzeby "biznesowej".
API? Najprościej zwracać jakiś pewnie jakies Either<Error, TakeResult> gdzie TakeResult zawiera nowego Bag i jakiś BagSlice z tymi wybranymi elementami.

0
Shalom napisał(a):

Czy w ogóle jest sens, żeby ta klasa były niemutowalna?

Nie rozumiem pytania. Jeśli potrzebujesz coś takiego, to takie coś napisz :) Przecież sensowność wynika z potrzeby "biznesowej".
API? Najprościej zwracać jakiś pewnie jakies Either<Error, TakeResult> gdzie TakeResult zawiera nowego Bag i jakiś BagSlice z tymi wybranymi elementami.

No właśnie zastanawia mnie potem kwestia użycia takiego API, gdzie "result" mam tak głęboko zaszyty. Szukam jakiegoś przykładu gdzie jest to rozwiązane podobnie, ale nie mogę znaleźć

3

Niemutowalne kolekcje mają np metodę do podziału kolekcji w pewnym miejscu, np io.vavr.collection.Vector.splitAt. Zwraca parę wektorów. W twoim przypadku torba.splitAt mogłoby zwracać dwie torby - jedną z 3 elementami i drugą bez tych 3 elementów. Potem na pierwszej robisz np .toList czy coś w ten deseń i już mamy kolekcję, której zawartość można sprawdzać wprost.

Co do losowości to nawet jeśli byłaby jakaś to powinna być powtarzalna, tak by zachodził warunek. x.take(3).equals(x.take(3)).

2

W kotlinie mosz w standardzie Pair więc możesz mieć Bag<T>{ fun take(i:Int) : Pair<List<T>,Bag> }
Z tym, że własny typ też ma zalety. Opakowanie tego w Either lub Option też jest raczej dobrym pomysłem.

To, że będzie zaszyty to nie jest problem - dzięki temu lepiej widać w API co może być rezultatem i jak z tym postępować.

1

Projekt API: fun take(n: Int): Bag, gdzie nowy Bag może mieć maksymalnie n elementów

0

Próbujesz za pomocą jednej metody zrobić wszystko - to dobre rozwiązanie na szybko, ale w praktyce jest mniej intuicyjne.

Twoje API byłoby prostsze gdybyś potraktował bag jak kolekcje.

Dobrze byłoby, gdyby po Twoim bagu dało się iterować, wówczas mógłbyś łatwo odczytać wartości jakie są w nim lub też przekonwertować na inną kolekcję.

Na bagu jak zrobisz randomTake wtedy ten bag zwróci Ci mniejszy bag.

0

A może niech Twoja klasa Bag opakowuje javowy Set (mieć set jako pole klasy) i taka metoda take(3) by brała 3 pierwsze elementy setu (a że jest to np HashSet, to będą to losowe elementy) i robiła na nich .remove().

0
mythflame napisał(a):

Cześć,

wyobrażam sobie klasę Bag, która zwiera jakieś elementy (nie da się sprawdzić jakie) i na której mogę zawołać metodę .take(3). W wyniku chciałbym dostać trzy losowe elementy z mojej torby + nowy obiekt Bag z aktualnym stanem. Jak najlepiej zaprojektować takie API? Czy w ogóle jest sens, żeby ta klasa były niemutowalna?

Jak piszesz o niemutowalności to najlepiej sprawdzić jak zrobili to w Haskellu. Dla List jest funkcja splitAt :: Int -> [a] -> ([a], [a]) która pobiera index typu Int i listę a zwraca parę list. Pierwsza zawiera elementy przed tym indeksem, a druga resztę. Dodatkowo jest dopisek że funkcja splitAt(index list) jest ekwiwalentem (take (index list), drop(index list)). Więc IHMO api zaprojektowane przez Ciebie jak najbardziej ma sens.

0

Dzięki za głosy i fajne przykłady. Zrobię własny typ zawierający nowy Bag + listę "wyjętych" elementów, ma to sens

Wibowit napisał(a):

Co do losowości to nawet jeśli byłaby jakaś to powinna być powtarzalna, tak by zachodził warunek. x.take(3).equals(x.take(3)).

Będę "mieszał" elementy gdzieś wcześniej, a przy take wyciągnę tylko N kolejnych. Powinno być okej.

1 użytkowników online, w tym zalogowanych: 0, gości: 1