* Задача от контролно 1, вариант 1, 22 ноември 2014 г.
Публикувано на 22 ноември 2014 в раздел ПИК3 Java.
Това е набързо написано (като за контролно :P) примерно решение на задачата от днешната контролна работа. Вероятно може много неща по него да се изгладят. Не е тествано въобще с реални данни - може да не е съвсем коректно. Моля ако някой има време, да го изпробва и да каже ако и къде има проблеми. Изтеглете сорс кода.
Задача 1. Създайте клас за фотоалбум (PhotoAlbum) с член променливи „брой страници“ (pagesCount – тип int) и списък от снимки (масив photos от тип FileInputStream). Максималният брой на снимките в един албум не трябва да превишава pagesCount*3 – това трябва да са границите на масива. Погрижете се новосъздаден фотоалбум да има минимум 10 страници. Освен конструктор с подадени параметри, трябва да създадете и конструктор по подразбиране, в който се създава нов празен албум с 16 страници.
Решение:
import java.io.*; class PhotoAlbum{ private int pagesCount; FileInputStream[] photos; public PhotoAlbum(){ this.pagesCount = 16; this.photos = new FileInputStream[this.pagesCount*3]; } public PhotoAlbum(int pagesCount, FileInputStream[] photos) throws Exception{ if(photos.length > pagesCount*3) throw new Exception("Too many photos"); this.setPagesCount(pagesCount); this.photos = new FileInputStream[this.pagesCount*3]; for(int i=0; i<photos.length; i++){ this.photos[i] = photos[i]; } } public int getPagesCount(){ return this.pagesCount; } public void setPagesCount(int pagesCount) throws Exception{ if(pagesCount<10) throw new Exception("Not enough pages for album"); else this.pagesCount = pagesCount; } }
Задача 2. В клас PhotoAlbum добавете следните методи:
a) static boolean equalPhotos(FileInputStream photo1, FileInputStream photo2) – методът трябва да сравни двата файла байт по байт и да върне true ако двете подадени снимки са с еднакво съдържание или false ако са различни;
Решение:
static boolean equalPhotos(FileInputStream photo1, FileInputStream photo2) throws IOException{ if(photo1.equals(photo2)) return true; BufferedInputStream input1 = new BufferedInputStream(photo1); BufferedInputStream input2 = new BufferedInputStream(photo2); int ch1=-1, ch2=-1; while ((ch1 = input1.read())!=-1){ ch2 = input2.read(); if (ch1 != ch2){ try{ if(input1 != null) input1.close(); if(input2 != null) input2.close(); } catch(IOException e){} return false; } } try{ if(input1 != null) input1.close(); if(input2 != null) input2.close(); } catch(IOException e){} return true; }
b) FileInputStream[] getDuplicates() – намира снимките, които имат дубликати и връща масив с указатели към тях;
Решение:
FileInputStream[] getDuplicates() throws IOException{ LinkedList<FileInputStream> duplicates = new LinkedList<FileInputStream>(); for (int i=0; i<this.photos.length-1; i++){ for (int j=i+1; j<photos.length; j++){ if (this.equalPhotos(this.photos[i], this.photos[j])){ duplicates.add(this.photos[i]); if(!duplicates.contains(this.photos[j])) duplicates.add(this.photos[j]); } } } return duplicates.toArray(new FileInputStream[duplicates.size()]); }
c) void addNewPhoto(FileInputStream newphoto) – методът добавя нова снимка в масива photos на следния принцип:
a. ако в албума има дублиращи се снимки, добавя новата на мястото на дублирана
b. ако няма дублиращи се снимки и има място в масива, добавя в края на масива
c. ако няма дублиращи се снимки и няма място в масива, хвърля Exception
Решение: // Като производителност е ужасно неефективен, но е един от най-бързите варианти за написване с оглед постигнатото дотук
void addNewPhoto(FileInputStream newphoto) throws IOException, Exception{ FileInputStream[] duplicates = this.getDuplicates(); if(duplicates.length>0){ int position = 0; for(int i=0; i<this.photos.length; i++){ if(photos[i].equals(duplicates[0])){ position =i; break; } } this.photos[position] = newphoto; } else{ for(int i=0; i<this.photos.length; i++){ if(this.photos[i] == null){ this.photos[i] = newphoto; return; } } throw new Exception("Album is full"); } }
Задача 3. Напишете клас BigPhotoAlbum, който наследява PhotoAlbum и добавя изискването броя на страниците на албума да е минимум 64.
Решение:
class BigPhotoAlbum extends PhotoAlbum{ public BigPhotoAlbum() throws Exception{ super(64, new FileInputStream[0]); } public BigPhotoAlbum(int pagesCount, FileInputStream[] photos) throws Exception{ super(pagesCount, photos); if(pagesCount<64) throw new Exception("Not enough pages for a big album"); } public void setPagesCount(int pagesCount) throws Exception{ if(pagesCount<64) throw new Exception("Not enough pages for a big album"); else super.setPagesCount(pagesCount); } }
Задача 4. Напишете клас с main метод, в който извършете следните действия:
a) Използвайки полиморфизъм създайте масив от 3 елемента, в който добавете два PhotoAlbum и един BigPhotoAlbum;
Решение:
PhotoAlbum[] list = new PhotoAlbum[3]; list[0] = new PhotoAlbum(); try{ list[1] = new BigPhotoAlbum(); } catch(Exception e){} list[2] = new PhotoAlbum();
b) Потърсете дублиращите се снимки във всеки от трите фотоалбума поотделно;
Решение:
FileInputStream[] duplicates1=null, duplicates2=null, duplicates3=null; try{ duplicates1 = list[0].getDuplicates(); duplicates2 = list[1].getDuplicates(); duplicates3 = list[2].getDuplicates(); } catch(IOException e){ System.out.println(e.getMessage()); }
c) Намерете общите дубликати на снимки измежду трите списъка намерени в b). Казано по друг начин – направете масив с тези снимки, които присъстват едновременно в трите албума.
LinkedList<FileInputStream> dups = new LinkedList<FileInputStream>(); for(int i=0; i<duplicates1.length; i++){ for(int j=0; j<duplicates2.length; j++){ for(int k=0; k<duplicates3.length; k++){ try{ if(PhotoAlbum.equalPhotos(duplicates1[i], duplicates2[j]) && PhotoAlbum.equalPhotos(duplicates2[j], duplicates3[k])){ dups.add(duplicates1[i]); if(!dups.contains(duplicates2[j])) dups.add(duplicates2[j]); if(!dups.contains(duplicates3[k])) dups.add(duplicates3[k]); } } catch(IOException e){ System.out.println(e.getMessage()); } } } } FileInputStream[] DuplicatesInAll = dups.toArray(new FileInputStream[dups.size()]);
Викам set метода на супер класа, защото нямам достъп до private променливата. Сигурно може да се напише по-елегантно.
Колкото до "по-приличен" set метод в супер класа... засега не ми идват идеи, които са различни от това да правя в него проверки, които се отнасят за дъщерния клас... А от гледна точка на капсулацията не е добре един клас да се грижи за валидация на данни за негови наследници. Ами ако добавим още един наследник? И още един? Ще трябва все да пренаписваме код в базовия клас. Не ми се струва като добра практика.
Ето още едно нещо, което ме издразни докато пишех решението - конструктора на BigPhotoAlbum() е по подразбиране, а ми се наложи да хвърля Exception. Освен да направя private конструктор и статичен init метод, друго не ми дойде на ум като решение... Но реших да не утежнявам задачата допълнително.
Здравейте!
Кому е необходимо да override - ваме сетъра ? Правим проверка и ако е >= 64 викаме метода на суперкласа в който проверяваме пак дали е < 10 ?! Та ние вече сме сигурни, че това условие е изпълнено... Не е ли по-подходящо да се напише по-приличен сетър в super - класа ?
public void setPagesCount(int pagesCount) throws Exception{
if(pagesCount<64) throw new Exception("Not enough pages for a big album");
else super.setPagesCount(pagesCount);
}
}