ITI0011:harjutus 10

Allikas: Kursused
Mine navigeerimisribale Mine otsikasti

Üldine

Ülesande kaitsmised: 16. - 18. märts
Kaust gitis: EX10

Ülesanne

Tundmatu logistikakeskus on sattunud seni nägemata probleemi otsa, nimelt tuli firma omanikelt idee luua priotiseeritud pakisüsteemi, mis saadab pakke vastavalt logistikakekuse poolt määratud järjekorrale. Idee oli määratud parendama tähtsate klientide rahololu transporditeenusega. Paraku on süsteem ööpäevaringselt töös ning ümberkirjutamine on antud fintantstingimustes võimatu. Firma peaarhitekti poolt tuli ettepanek laiendada süsteemi standardpakke ja vahetada iga logistikakeskuse väljastusautomaadi PackageProvider uue vastu nii, et oleks täidetud järgmised tingimused:

  • Väljastusautomaat eelistab alati PremiumPackage tüüpi pakke
  • PremiumPackage pakkidest tuleb eelistada kõrgema prioriteediga (suurema priority väärtusega pakk)
  • Kui kaks PremiumPackage tüüpi pakki omavad sama prioriteeti, siis tuleb arvestada klientide summaarset prioriteeti (receiver.priority + sender.priority). Identsete prioriteetidega pakke ei järjestata (vahet pole, kumb enne väljastatakse)
  • Tavaliste pakkide puhul arvestada ainult klientide summaarset prioriteeti.
  • Väljastusautomaati saab lisada vaid erinevaid instantse. Ehk siis kui pakiautomaadis juba on instants olemas, siis sedasama sinna lisada ei saa. Lisamise korral midagi ei juhtu.

Ülesande jaoks on kaasa antud mõned java-failid (vaata allpool Mall sektsioonist). Interface'e muuta ei tohi. Klasse võite täiendada, aga olemasolev funktsionaalsus peab säilima.

Ülesande jaoks peate looma:

  • PremiumPackage klassi, mis laiendab Package klassi ja lisab eelnimetatud funktsionaalsuse. Klassis peavad olema int getPriority() ja setPriority(int) meetodid.
  • OrderedPackageProvider klassi, mis implementeerib PackageProvider liidest (interface) ja täidab eelnimetatud tingimused.

Mall

Package.java <source lang="java"> /**

* Package class.
*/

public class Package {

   /**
    * Package number printed on page.
    */
   protected String packageNumber;
   /**
    * Package width in cm.
    */
   protected int width;
   /**
    * Package height in cm.
    */
   protected int height;
   /**
    * Package sender.
    */
   protected Customer sender;
   /**
    * Package receiver.
    */
   protected Customer receiver;
   /**
    * Get receiver.
    *
    * @return Receiver customer
    */
   public Customer getReceiver() {
       return receiver;
   }
   /**
    * Package cunstroctor without arguments.
    */
   public Package() {
   }
   /**
    * Package constructor.
    *
    * @param packageNumber Package number printed on package
    * @param width         Package width in cm
    * @param height        Package height in cm
    */
   public Package(String packageNumber, int width, int height) {
       this.packageNumber = packageNumber;
       this.width = width;
       this.height = height;
   }
   /**
    * Set receiver.
    *
    * @param receiver Receiver customer
    */
   public void setReceiver(Customer receiver) {
       this.receiver = receiver;
   }
   /**
    * Get sender.
    *
    * @return Sender customer
    */
   public Customer getSender() {
       return sender;
   }
   /**
    * Set sender.
    *
    * @param sender Sender customer
    */
   public void setSender(Customer sender) {
       this.sender = sender;
   }
   /**
    * Get package number.
    *
    * @return Package number
    */
   public String getPackageNumber() {
       return packageNumber;
   }
   /**
    * Set package number
    *
    * @param packageNumber Package number
    */
   public void setPackageNumber(String packageNumber) {
       this.packageNumber = packageNumber;
   }
   /**
    * Get package height.
    *
    * @return Package height
    */
   public int getHeight() {
       return height;
   }
   /**
    * Set package height.
    *
    * @param height Package height.
    */
   public void setHeight(int height) {
       this.height = height;
   }
   /**
    * Get package width.
    *
    * @return Package width.
    */
   public int getWidth() {
       return width;
   }
   /**
    * Get package width.
    *
    * @param width Package width.
    */
   public void setWidth(int width) {
       this.width = width;
   }

}


</source>

Customer.java <source lang="java"> /**

* Customer class.
*/

public class Customer {

   /**
    * Customer priority.
    * 0 < priority < 1000
    */
   private int priority;
   /**
    * Customer name.
    */
   private String name;
   /**
    * Customer address.
    */
   private String address;
   /**
    * Customer constructor without arguments.
    */
   public Customer() {
   }
   /**
    * Customer constructor.
    *
    * @param priority Customer prority
    * @param name     Customer name
    * @param address  Customer address
    */
   public Customer(int priority, String name, String address) {
       this.priority = priority;
       this.name = name;
       this.address = address;
   }


   /**
    * Get customer address.
    *
    * @return Customer address
    */
   public String getAddress() {
       return address;
   }
   /**
    * Set customer address.
    *
    * @param address Customer address
    */
   public void setAddress(String address) {
       this.address = address;
   }
   /**
    * Get customer name.
    *
    * @return Customer name
    */
   public String getName() {
       return name;
   }
   /**
    * Set customer name.
    *
    * @param name Customer name
    */
   public void setName(String name) {
       this.name = name;
   }
   /**
    * Get customer priority.
    *
    * @return Customer priority
    */
   public int getPriority() {
       return priority;
   }
   /**
    * Set customer priority
    *
    * @param priority Customer priority
    */
   public void setPriority(int priority) {
       this.priority = priority;
   }

}


</source>

PackageProvider.java <source lang="java"> import java.util.List;

/**

* PackageProvider interface.
*/

public interface PackageProvider {

   /**
    * Get next package in the queue.
    *
    * @return Next package
    */
   Package getNextPackage();
   /**
    * Add new package to queue.
    *
    * @param packageToAdd A new package to add
    */
   void addPackage(Package packageToAdd);
   /**
    * Returns whether the provider hax next package or not.
    *
    * @return next package exists
    */
   boolean hasNextPackage();
   /**
    * Set package filter to queue.
    *
    * @param packageFilter PackageFilter
    */
   void setPackageFilter(PackageFilter packageFilter);
   /**
    * Get package filter.
    *
    * @return packageFilter
    */
   PackageFilter getPackageFilter();
   /**
    * Sets the package provider where all not valid packages are sent.
    * If package filter is set and a new package is add which is not valid,
    * the package is sent to this provider.
    *
    * @param packageProvider
    */
   void setBrokenPackageProvider(PackageProvider packageProvider);
   /**
    * Returns broken package provider where invalid packages are sent.
    *
    * @return
    */
   PackageProvider getBrokenPackageProvider();
   /**
    * Get packages as list (not ordered).
    *
    * @return Package list
    */
   List<Package> getPackages();
   /**
    * Get all sender packages (not ordered).
    *
    * @param customer Sender customer
    * @return Ordered list of sender packages
    */
   List<Package> findAllPackagesBySender(Customer customer);
   /**
    * Get all reciever packages (not ordered).
    *
    * @param customer Receiver customer
    * @return Ordered list of receiver packages
    */
   List<Package> findAllPackagesByReceiver(Customer customer);

}

</source>

PackageFilter.java <source lang="java"> /**

* Package filtering interface.
*/

public interface PackageFilter {

   /**
    * Validate package information.
    *
    * @param p Package to validate.
    * @return Whether the package information is correct.
    */
   boolean isValid(Package p);

}

</source>

Põhiosa jaoks te ei pea PackageFilter implementatsiooni (ehk siis klassi, mis implementeerib filtrit) looma. Aga get ja set meetodid peavad ikka töötama.

Koodinäide

Allpool näites getPackages() meetod tagastab pakid juba sorteeritult. Teie kood seda tegema ei pea (aga võib). Oluline on, et getNextPackage() tagastaks pakid õiges järjekorras.

<source lang="java"> OrderedPackageProvider pp = new OrderedPackageProvider();

Customer c1 = new Customer(12, "kati", "põdra"); Customer c2 = new Customer(10, "mati", "metsa"); Customer c3 = new Customer(12, "vati", "villa"); // notation in the name: // s: priority of the sender, r: priority of the receiver Package p1 = new Package("p (s:12 r:10)", 100, 100); p1.setSender(c1); p1.setReceiver(c2); Package p2 = new Package("p (s:10 r:12)", 100, 120); p2.setSender(c2); p2.setReceiver(c1); // notation in the name: // pp priority s: priority of the sender, r: priority of the receiver PremiumPackage pp1 = new PremiumPackage(10, "pp 10 (s:12 r:10)", 100, 100); PremiumPackage pp2 = new PremiumPackage(10, "pp 10 (s:12 r:12)", 100, 100); PremiumPackage pp3 = new PremiumPackage(12, "pp 12 (s:12 r:12)", 100, 100);

pp1.setSender(c1); pp1.setReceiver(c2);

pp2.setSender(c1); pp2.setReceiver(c3);

pp3.setSender(c1); pp3.setReceiver(c3);

pp.addPackage(p1); pp.addPackage(p2); pp.addPackage(pp2); pp.addPackage(pp1); pp.addPackage(pp3); // we use lambda expression pp.getPackages().forEach(p -> System.out.println(p.getPackageNumber())); // if Package.toString is implemented to print out package number, we could use: // pp.getPackages().forEach(System.out::println);

// the above is the same as: /* for (Package p : pp.getPackages()) {

   System.out.println(p.getPackageNumber());

}

  • /

// take the next (first) package pp.getNextPackage(); // 4 remains: System.out.println(pp.getPackages().size()); pp.getPackages().forEach(p -> System.out.println(p.getPackageNumber()));

// add a new package PremiumPackage pp4 = new PremiumPackage(13, "pp 13 (s:12 r:12)", 100, 100); pp4.setSender(c1); pp4.setReceiver(c3); pp.addPackage(pp4); System.out.println("After adding a new one:"); pp.getPackages().forEach(p -> System.out.println(p.getPackageNumber()));

// take 4 more packages pp.getNextPackage(); pp.getNextPackage(); pp.getNextPackage(); pp.getNextPackage();

// do we have more? System.out.println(pp.hasNextPackage()); // do we? System.out.println(pp.getNextPackage()); // ok

// do we still have more? System.out.println(pp.hasNextPackage()); // NO! System.out.println(pp.getNextPackage()); // no more -> null </source>

Väljund:

pp 12 (s:12 r:12)
pp 10 (s:12 r:12)
pp 10 (s:12 r:10)
p (s:12 r:10)
p (s:10 r:12)
4
pp 10 (s:12 r:12)
pp 10 (s:12 r:10)
p (s:12 r:10)
p (s:10 r:12)
After adding a new one:
pp 13 (s:12 r:12)
pp 10 (s:12 r:12)
pp 10 (s:12 r:10)
p (s:12 r:10)
p (s:10 r:12)
true
p (s:10 r:12)
false
null

Lisaosa (0.5p)

Sageli satub pakiringlusesse pakke, mis ei vasta ettevõtte poolt ettekirjuatud nõudmistele. Implementeerida PackageFilter alusel PackageProviderisse sisendfilter, mis kontrollib pakkide valiidsust. Klassi nimi peab olema OrderedPackageFilter. Kõik pakid peavad vastama tingimustele:

  • Receiver, sender ei ole tühi, receiveril on nimi (mitte tühi sõne).
  • Receiver, sender aadress ei ole tühi
  • Receiver, sender priority on suurem kui 0 ja väiksem kui 1000
  • Kõrgus ja laius on rangelt 0-st suuremad ja rangelt 1000-st väiksemad
  • Paki number ei ole tühi
  • Receiver ei ühti senderiga (kliendi andmed peavad erinema)

PremiumPackage puhul:

  • Priority rangelt suurem kui 0 ja rangelt väiksem kui 1000.

Pakid, mis filtrist läbi ei lähe (isValid tagastab false) pannakse teie OrderedPackageProvider objekti poolt teise PackageProviderisse, mis on määratud setBrokenPackageProvider meetodiga. Kui sellist broken package providerit pole lisatud, siis mittekorrektsed pakid lihtsalt kaovad ära.

Mis tuleb teha:

  • kirjutate klassi OrderedPackageFilter mis implementeerib PackageFilter liidest.
  • loodud klassi isValid meetod peab tagastab true, kui etteantud pakk rahuldab kõiki eelpool mainitud tingimusi. Muul juhul tagastab false.
  • OrderedPackageProvider klassis peate addPackage meetodis kontrollima, et kui objektile on määratud filter (uue instantsi puhul on filter vaikimisi null, seda saab määrata eraldi, vt all koodinäide), siis kontrollite filtri isValid meetodi tagastust. Kui isValid tagastab true, lisate paki oma pakkide nimekirja (nii, nagu te tegite seda põhiosas ilma filtrita). Kui isValid tagastab false, lisate paki brokenPackageProvider objekti (kuna see realiseerib samamoodi PackageProvider liidest, on tal meetod addPackage - seda peategi kasutama). Kui brokenPackageProvider on null (ehk objekti pole määratud teie OrderedPackageProvider'ile), siis pakki ei lisata kuhugi.

Te ei pea looma uut klassi BrokenPackageProvider (või kui siis vaid testimiseks). Automaattestimise käigus kasutatakse meie loodud objekte seal.

Testimine

Lisaosa testides on üks suur test (miljoni objektiga). See test lisab 1000000 pakki teie providerisse. Ajalimiit on 10 sekundit. Selle lahendamiseks peaks kasutama näiteks TreeSet (https://docs.oracle.com/javase/8/docs/api/java/util/TreeSet.html) andmestruktuuri pakkide hoidmiseks. Kõik muud variandid (kui üritate pidevalt sortida jms) jäävad liiga aeglaseks.

Koodinäide

Filtri testimiseks (eeldus on, et OrderedPackageFilter on realiseeritud):

<source lang="java"> PackageProvider packageProvider = new OrderedPackageProvider(); // let's confirm that the list is empty: System.out.println(packageProvider.getPackages().size());

// bad package - empty package number, no customers Package badPackage = new Package("", 10, 10);

// as by default there is no filter, this package is added: packageProvider.addPackage(badPackage); // let's confirm that there is one element: System.out.println(packageProvider.getPackages().size());

// create your own package filter instance PackageFilter orderedPackageFilter = new OrderedPackageFilter(); // let's add this filter to provider: packageProvider.setPackageFilter(orderedPackageFilter);

// another bad package badPackage = new Package("", 0, 0); // very bad packageProvider.addPackage(badPackage); // this package should not go the the list, therefore the size should be 1: System.out.println(packageProvider.getPackages().size());

// we can validate packages directly in filter also: System.out.println(orderedPackageFilter.isValid(badPackage)); // false

badPackage = new PremiumPackage(0, "PAKKK", 1, 2); System.out.println(orderedPackageFilter.isValid(badPackage)); // false

// let's create some valid packages too Customer c1 = new Customer(10, "mati", "metsas"); Customer c2 = new Customer(11, "kati", "kaugel");

badPackage = new PremiumPackage(1, "PAKKK", 1, 2); badPackage.setSender(c1); badPackage.setReceiver(c2); System.out.println(orderedPackageFilter.isValid(badPackage)); // true

Customer c3 = new Customer(10, "mati", "metsas"); // same data as c1 badPackage = new PremiumPackage(1, "Must have", 10, 11); badPackage.setSender(c1); badPackage.setReceiver(c3); System.out.println(orderedPackageFilter.isValid(badPackage)); // false

// we can remove the filter also packageProvider.setPackageFilter(null); badPackage = new PremiumPackage(0, "pakk matile", 11, 0); // no sender/receiver

// now everything should be added, again packageProvider.addPackage(badPackage); System.out.println(packageProvider.getPackages().size()); </source>

Oodatav väljund:

0
1
1
false
false
true
false
2

Broken package provider'i testimiseks on järgmine kood. Tähelepanu tuleb pöörata sellele, et see kood automaatselt käima ei lähe. Kuna BrokenPackageProvider (mida selles koodis on kasutatud) ei ole tegelikult selle ülesande osa, siis ei ole selle koodi siin ka välja toodud. Mõte on selles, et te saate sinna määrata ükskõik millise PackageProvider interface'i implementeeriva klassi. Seega põhimõtteliselt võite sinna ette anda ka oma OrderedPackageProvideri.

See kood tuleks panna eelmise koodi lõppu (kuna kasutab samu muutujaid jms): <source lang="java"> // let's try brokenPackageProvider // we have creates a new class BrokenPackageProvider // which is just an implementation of PackageProvider. // NOTE! you don't have to create BrokenPackageProvider // and don't need to upload it. // to run this test, just create class: // class BrokenPackageProvider implements PackageProvider // and implement just addPackage and getPackages methods PackageProvider broken = new BrokenPackageProvider(); packageProvider.setBrokenPackageProvider(broken); // let's add the filter again packageProvider.setPackageFilter(orderedPackageFilter);

System.out.println("Test broken package provider"); // we should start with 0 System.out.println("broken provider: " + broken.getPackages().size()); // the main provider is here: System.out.println("main provider: " + packageProvider.getPackages().size());

System.out.println("adding \"broken\" package"); packageProvider.addPackage(badPackage);

// broken package provider should have one package in it: System.out.println("broken provider: " + broken.getPackages().size()); // the main provider should remain where it was System.out.println("main provider: " + packageProvider.getPackages().size()); </source>

Oodatav väljund:

Test broken package provider
broken provider: 0
main provider: 2
adding "broken" package
broken provider: 1
main provider: 2