0.1 Hierarchia klas 0.1.1 Diagram 0.1.2 Krótkie wyjaśnienie Po pierwsze to jest tylko przykładowe rozwiązanie. Zarówno na wtorkowych i czwartkowych ćwiczeniach odbiegaliśmy od niego, ale nie wiele. Na diagramie znajdują się wszystkie klasy, pola i metody jakie należy później zaimplementować. Są też narysowane relacje. Ważne elementy to: abstrakcyjna klasa Krasnolud, oraz dziedziczenie podklas KrasnoludLos, KrasnoludStatystyk i KrasnoludWypelnienie. Kolejny element który jest w relacji to kontener, (który nie jest workiem), do którego Bilbo odkłada skarby (te dla siebie) - czyli Skarby. Obiekt tej klasy (będzie jeden dla Bilba i dla każdego z worków), zawiera referencje do wielu obiektów klas Skarb. Dlatego jest zaznaczone to na diagramie (0..* do 1). Warto zwrócić uwagę na klasy OdpowiedziBilbo (później obiekt nazywa się widokworków (w klasie Krasnolud)), oraz WidokWorka. Te klasy zostały utworzone po to abyśmy mogli pokazać nie pełne informacje (o Bilbie w przypadku OdpowiedziBilbo, oraz Worku w przypadku WidokWorka) klasie Krasnolud. Gdyż z treści zadania wynika, że Krasnolud nie powinien mieć zbyt dużo informacji. Będziemy wysyłać opakowane Worek w WidokWorka tzn WidokWorka ma prywatne pole (obiekt) Worek i metody, które umożliwiają te operacje, na które zezwolimy klasie Krasnolud. Trochę o hermetyzacji. Czyli gdzie i co mamy public/protected/private. Bardzo ważna rzecz, aby nie zapomnieć o ukrywaniu implementacji. Jest to jedna z podstawowych spraw programowania obiektowego. Komuś kto będzie używał naszej klasy/klas udostępniamy takie metody aby nie mógł zmienić jego wewnętrznego stanu w sposób bezpośredni. 1
0.2 Implementacja Opiszę nietrywialne miejsca (na niebiesko to moje komentarze). Po więcej trzeba się pytać. 0.2.1 Bilbo public class Bilbo { private Skarby skarby = new Skarby(); public void rozdzeil(skarb[] skarby, Krasnolud[] krasnoludy, Worek[] worki) { worki = rozstawworki(krasnoludy, worki); int k = 0; k jest zmienną która oznacza aktualnego krasnoluda (którego się pytam). Warto zauważyć że jest w arytmetyce modulo liczba krasnoludów. for (int i = 0; i < skarby.length; i++) { int zapytanych = 0; Obliczam ile już zapytałem, ponieważ gdy zapytam wszystkich, muszę rozdzielić skarby (nie chciałbym się zapętlić). while (zapytanych < krasnoludy.length &&!krasnoludy[k].czychceszskarb()) { zapytanych++; k = (k + 1) % krasnoludy.length; if (zapytanych == krasnoludy.length) { Gdy zapytam wszystkich, (nikt nie chciał skarbu), to rozdzielam. przekazzawartosc(krasnoludy, worki); continue; if (worki[k].czypomiesci(skarby[i])) worki[k].dodaj(skarby[i]); else Zabieram skarby gdy krasnolud jest zbyt zachłanny. zabiezskarby(worki[k], skarby[i]); i++; przekazzawartosc(krasnoludy, worki); wypiszrezultat(krasnoludy); private void wypiszrezultat(krasnolud[] krasnoludy) { for (int i = 0; i < krasnoludy.length; i++) { System.out.println("Krasnolud " + i + " dosta 3 nast^epuj 1 ce skarby:"); krasnoludy[i].wypiszskarby(); 2
private void zabiezskarby(worek worek, Skarb skarb) { Skarby to pole w obiekcie klasy Bilbo, gdzie przechowuję zabrane skarby, warto zauważyć, że oprócz skarbów, które są w worku mam jeszcze jeden w ręce. skarby.dodaj(worek.oproznij()); skarby.dodaj(skarb); private Worek[] rozstawworki(krasnolud[] krasnoludy, Worek[] worki) { for (int i = 0; i < worki.length; i++) { Daję krasnoludom możliwość zapytania Bilba. Wysyłam im obiekt który może utworzyć tylko Bilbo (bo on ma dostęp do worków). krasnoludy[i].setwidokworkow(new OdpowiedziBilbo(worki, i)); return worki; private void przekazzawartosc(krasnolud[] krasnoludy, Worek[] worki) { for (int i = 0; i < worki.length; i++) { krasnoludy[i].dodaj(worki[i].oproznij()); 0.2.2 Krasnolud public abstract class Krasnolud { To nie są skarby w worku Krasnoluda, tylko te które uzyskał po tym jak Bilbo rozdzielił do worków i żaden Krasnolud nie chciał skarbu. protected Skarby skarby = new Skarby(); protected OdpowiedziBilbo widokworkow; public abstract boolean czychceszskarb(); public void dodaj(skarby skarby) { skarby.dodaj(skarby); public void setwidokworkow(odpowiedzibilbo workow) { this.widokworkow = workow; public void wypiszskarby() { System.out.println(skarby); 3
0.2.3 KrasnoludLos Nic specjalnego. public class KrasnoludLos extends Krasnolud { public boolean czychceszskarb() { return Math.random() < 0.5; 0.2.4 KrasnoludStatystyk public class KrasnoludStatystyk extends Krasnolud { public boolean czychceszskarb() { Aby policzyć średnią, krasnolud odpytuje Bilba (liczy skarby, oraz pojemności). int ileskarbow = policzskarby(); if (ileskarbow == 0) return true; WidokWorka mojworek = widokworkow.dajmoj(); return mojworek.pojemnosc() - mojworek.wypelnienie() >= policzpojemnoscrozdanych() / ileskarbow; private int policzpojemnoscrozdanych() { int s = 0; for (int i = 0; i < widokworkow.ileworkow(); i++) { s += widokworkow.daj(i).wypelnienie(); return 0; private int policzskarby() { int s = 0; for (int i = 0; i < widokworkow.ileworkow(); i++) { s += widokworkow.daj(i).ileskarbow(); return s; 0.2.5 KrasnoludWypelnienie public class KrasnoludWypelnienie extends Krasnolud { private double procent; public KrasnoludWypelnienie(double procent) { 4
this.procent = procent; public boolean czychceszskarb() { WidokWorka moj = widokworkow.dajmoj(); W treści zadania mieliśmy informacje, że również do swojego worka krasnolud musi odwoływać się za pomocą Bilba. return (double) moj.wypelnienie() / (double) moj.pojemnosc() <= procent; 0.2.6 OdpowiedziBilbo public class OdpowiedziBilbo { private WidokWorka[] worki; private int numerworka; public OdpowiedziBilbo(Worek[] worki, int i) { this.worki = new WidokWorka[worki.length]; this.numerworka = i; for (int j = 0; j < worki.length; j++) { this.worki[i] = new WidokWorka(worki[i]); public int ileworkow(){ return worki.length; public WidokWorka daj(int numer) { return worki[numer]; public WidokWorka dajmoj() { return daj(numerworka); 0.2.7 Skarb public class Skarb { private int rozmiar; public int rozmiar() { return rozmiar; public String tostring() { 5
return "Skarb rozmiaru: " + rozmiar; 0.2.8 Skarby Skarby to klasa służąca za kontener przechowujący obiekty Skarb. Warto przeczytać sobie implementację, ponieważ bardzo często jest po prostu identyczna. Gdy potrzebujemy kontenera. public class Skarby { private Skarb[] skarby = new Skarb[0]; private int rozmiar = 0; public void dodaj(skarb s) { if (skarby.length == rozmiar) powieksz(); skarby[rozmiar++] = s; private void powieksz() { Skarb[] tmp = new Skarb[skarby.length * 2 + 1]; for (int i = 0; i < skarby.length; i++) { tmp[i] = skarby[i]; skarby = tmp; public void dodaj(skarby s) { for (int i = 0; i < s.rozmiar; i++) { dodaj(s.skarby[i]); public String tostring() { StringBuilder r = new StringBuilder(); for (int i = 0; i < skarby.length; i++) { r.append(skarby.tostring()); r.append("\n"); return r.tostring(); public int rozmiar() { return rozmiar; 0.2.9 Worek public class Worek { 6
private int pojemnosc; private int wypelnienie; private Skarby skarby = new Skarby(); public boolean czypusty() { return ileskarbow() == 0; public int ileskarbow() { return skarby.rozmiar(); public boolean czypomiesci(skarb s) { return wypelnienie + s.rozmiar() <= pojemnosc; public void dodaj(skarb s) { skarby.dodaj(s); public Skarby oproznij() { Skarby s = skarby; wypelnienie = 0; skarby = new Skarby(); return s; public int wypelnienie() { return wypelnienie; public int pojemnosc() { return pojemnosc; 0.2.10 WidokWorka public class WidokWorka { private Worek worek; public WidokWorka(Worek worek) { this.worek = worek; public int ileskarbow() { return worek.ileskarbow(); public int wypelnienie() { 7
return worek.wypelnienie(); public int pojemnosc() { return worek.pojemnosc(); 8