* Задача от контролно 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);
}
}