Wykorzystanie interfejsów w przykładowym programie

0

Witam

Pracuję z książką "Java w 21 dni" i pomocniczo z "Java Podstawy". Pierwsza z książek ma rozdziały podzielone na dni. W związku z tym po 7 dniach chciałem podsumować cały "tydzień" pisząc jakiś prosty program, który będzie w sobie zawierał tematy, które w tym "tygodniu" się mieściły.

W ramach mojego podsumowania zabrałem się do prostego programu, który nie ma robić nic innego jak tylko tworzyć tablicę, posortować ją i wyświetlić ile razy dany element w niej się powtarza. (Elementy i wielkość tablicy pobrane z klawiatury).

Program jest pewnie dosyć zagmatwany jeśli idzie o jego strukturę, jednak chciałem w nim wszystko "zmieścić".

Sprawą, przy której się zatrzymałem to interfejsy, ponieważ nie jestem pewien czy dobrze je rozumiem a tym bardziej nie wiem czy w ogóle można ich użyć w moim programie.

Z tego co zrozumiałem interfejsu używamy, gdy chcemy wykonać jakieś działania na już utworzonych obiektach jak np. właśnie sortowanie ich czy wykonanie innych czynności na (w moim przypadku) elementach mojej nieszczęsnej tablicy. Z tego co zrozumiałem interfejs powinien być jak najbardziej uniwersalny, żeby można było podpiąć pod niego każdy obiekt. Nie mam jednak pojęcia jak miałoby to wyglądać w praktyce i czy w moim programie da się ich jakoś sensownie użyć.

Rozjaśnilibyście może mi trochę ten temat i pomogli jakoś w kwestii stworzenia interfejsu w moim programie? Poniżej zamieszczam kod:

Pobieram wielkość tablicy i ją zwracam:

package Table;

import java.util.*;

class ArraySize {
	Scanner in = new Scanner (System.in);
	private int elIn;
	
	
	// Metoda odpowiadająca za pobór wielkości tablicy
	public void inSize() {
		
		 elIn = in.nextInt();
		 
		
	}
	
	
	// Zwraca rozmiar tablicy
	public int getSize() {
		
		return elIn;

	}
	
	


}


Tworzę tablicę na podstawie danych z klasy powyższej. W tej klasie dodatkowo sortuję jej elementy metodą "quicksort".

package Table;
import java.util.*;
class CreateArray {
	
	//Deklaracja tablicy
	int [] tablica;
	private Scanner in = new Scanner(System.in);
	ArraySize tabSize = new ArraySize();
	
	//Metoda przyjmująca zmienną indeks typu int, tworzy tablice i inicjuje jej wielkość. Wielkość będzie pobrana z innej metody w innej klasie.
	public void StworzTablice (int indeks) {
	tablica = new int[indeks]; 
	
	
	}
	
	//Metoda zwracająca długość tablicy.
	int getDlugosc() {
		return tablica.length;
	}
	
	//Pętla wypełnia tablicę elementami pobranymi z klawiatury. Metoda przyjmuje zmienną typu int,. która określa do kiedy pętla ma się wykonywać.
	public void WypelnijTablice(int indk) {
	for (int i=0; i<indk; i++) {
		tablica[i] = in.nextInt();
		
			
	}
	
	
	}
	
	void sortowanie() {
		Arrays.sort(tablica);
	}
	

	}

Wyświetlam tablicę.

package Table;

class ViewArray {
	
	public void NArray(int Value){
		System.out.println("Tablica " + Value + " elementowa.");
	}
	
	
	public void VArray(int lgth, int[] tab) {
		
		System.out.print("[ ");
		for(int i=0; i<lgth; i++) {
			System.out.print(" " + tab[i] + " ");
		}
		System.out.print(" ]");
	}
	

}

Ta metoda ma za zadanie zliczenie ile razy dany element tablicy się powtarza. Nie jest skończona, bo tutaj zacząłem się zastanawiać czy da się w tym celu użyć jakoś interfejsu?

package Table;

public class SprawdzIle {
	
	void SprIle(int[] tablica ) {
		int licznik=0, element=0;
		
		
		for (int i=0; i< tablica.length; i++) {
			
		
			for (int j=0; j< tablica.length; j++) {
				
				if (tablica[i] == tablica[j]) 
				licznik++;
				
				
			}
			
			System.out.print(tablica[i] + " = " + licznik + ", ");
			
			licznik = 0;
			
		}
	}

}

No i main

package Table;

import java.util.Arrays;

public class main {
	public static void main(String [] args) throws NullPointerException {
		ArraySize rozmiar = new ArraySize();
		ViewArray vt = new ViewArray();
		CreateArray ct = new CreateArray();
		SprawdzIle spr = new SprawdzIle();
		System.out.println("Wprowadz rozmiar tablicy");
		rozmiar.inSize();
		vt.NArray(rozmiar.getSize()); //Wyświetla ile elementów ma tablica. Metoda przyjmuje za argument wartość z metody getSize()
		System.out.println("Wprowadz elementy tablicy: ");
		ct.StworzTablice(rozmiar.getSize()); // Wywołuje metodę odpowiedzialną za rozmiar tablicy, metoda przyjmuje za argument wartość zwróconą przez getSize()
		ct.WypelnijTablice(ct.getDlugosc());
		System.out.println("Lista elementów w tablicy");
		ct.sortowanie();
		vt.VArray(ct.getDlugosc(), ct.tablica);
		System.out.println();
		System.out.println("Elementy powtarzają się: ");
		spr.SprIle(ct.tablica);
	}

}

0

Przestudiuj sobie to.

0

Przeczytałem to, ale ciągle średnio to rozumiem.

Autor najpierw zrobił interfejs, który zawierał same puste metody, a potem zaimplementował je do klas, które i tak musiały wykonywać działania w tych metodach.

Nie rozumiem po co więc tworzyć taki interfejs?

Przenosząc to do mojego programu, musiałbym zrobić metody, które odpowiadają za wyliczenie ile razy dany element się powtarza, a następnie zrobić klasę, która zaimplementuje cały interfejs, ale będzie mimo wszystko wykonywać to działanie?

0

Bo dzięki temu możesz w kodzie wygodnie zmienic implementacje na inną.
W twoim kodzie żadna klasa nie ma sensu i w ogóle źle to napisałeś, stąd też problem ze zrozumieniem interfejsów. Klasa określa typ obiektu i tylko w wyjątkowych sytuacjach określa jakąś "czynność". Czynności zwykle są metodami/funkcjami, a u ciebie wszystko jest klasą o_O

Co do interfejsów, wyobraź sobie że masz w kodzie użycie List<String> i w 50 różnych miejscach masz powtórzone List<String> a sam obiekt tworzysz w jednym miejscu w main(). Możesz sobie tam stworzyć ArrayList<String> czy LinkedList<String> bo i jedno i drugie "pasuje" do List<String>.
A teraz pomyśl co by było jakbyś na początku wszędzie dał ArrayList<String>. Zmiana tego na LinkedList<String> wymagałaby zmiany w tych 50 miejscach w kodzie...
Już nawet nie wspomnę co byś zrobił jakby użytkownik miał sam wybrać typ podając jakiś input z klawiatury! Co byś wtedy zrobił?

0

Nie rozumiem. Klasa jest przecież początkiem wszystkiego, jak mógłbym napisać bez tego metodę/funkcję? Jak mógłbym w takim razie zmodyfikować swój kod, żeby nabrał sensu?

Uczę się samodzielnie, zakładam, że po prostu czegoś nie zrozumiałem, stąd te babole.

Czyli rozumiem, że zmieniając interfejs, nie trzeba w 50 innych miejscach wprowadzać żadnych zmian, tylko w 1 interfejsie?

1

Klasa jest przecież początkiem wszystkiego.

+10 Fajnie to zabrzmiało ;)

Czyli rozumiem, że zmieniając interfejs, nie trzeba w 50 innych miejscach wprowadzać żadnych zmian, tylko w 1 interfejsie?

Nie, do końca. Zmieniając interfejs musisz zmienić klasy, które ten interfejs implementują (jeśli usuniesz metdę, a klasy implementujące interfejs nie używają adnotacji @Override i metoda ta nie była używana, zmiana nie jest potrzebna. Jeśli dodasz metodę domyślną do interfejsu zmiana nie będzie potrzebna. Jednak "niekompatybilne" zmiany w interfejsie trzeba mocno przemyśleć).

Pisane na kolanie w okienku forum:

public class MyArray {
    private final int[] array;

    public MyArray(int size) {
        array = new array[size];
    }

    public String toString() {
        return Arrays.toString(array);
    }

    public int getLength() {
        return array.length;
    }

    public void set(int index, int value) {
        array[index] = value;
    }

    public static void main(String [] args) throws NullPointerException {
        Scanner scanner = new Scanner(System.in);
        System.out.println("Wprowadz rozmiar tablicy");
        MyArray myArray = new MyArray(scanner.nextInt());
        System.out.println(myArray.getSize());
        for (int index = 0; index < myArray.getSize(), index++) {
            myArray.set(index, scanner.nextInt());
        }

        // MyArray sortedArray = myArray.sorted();
        // System.out(myArray.duplicatedEntries();
    }
}

Na koniec polecę trochę prywatą - możesz rzucić okiem do artykułu, który napisałem Interfejsy w języku Java. Powinno to rozwiać Twoje wątpliwości dotyczące interfejsów.

1

Czyli rozumiem, że zmieniając interfejs, nie trzeba w 50 innych miejscach wprowadzać żadnych zmian, tylko w 1 interfejsie?

Nie no nic nie zrozumiałeś ;] Możesz zmienić IMPLEMENTACJE na inną, o ile obie korzystają z tego samego interfejsu...

    void x(List<String> list){
       // cośtam
    }
    void y(List<String> list){
       // cośtam
    }
    void z(List<String> list){
       // cośtam
    }
    void v(List<String> list){
       // cośtam
    }

//
public static void main(String[] args){
    List<String> lista1 = new ArrayList<>();
    x(lista1);
    y(lista1);
    z(lista1);
    v(lista1);
    List<String> lista2 = new LinkedList<>();
    x(lista2);
    y(lista2);
    z(lista2);
    v(lista2);
}

To wszystko zadziała, bo zarówno ArrayList i LinkedList to List. Ale teraz załózmy że nie używamy interfejsu i wszędzie używamy konkretnych klas:

    void x(ArrayList<String> list){
       // cośtam
    }
    void y(ArrayList<String> list){
       // cośtam
    }
    void z(ArrayList<String> list){
       // cośtam
    }
    void v(ArrayList<String> list){
       // cośtam
    }

I teraz nagle ten main() wyżej nie działa już dla LinkedList bo typ nie jest zgodny z ArrayList. Więc żeby użyć LinkedList musiałbyś zmienić typ w tych metodach.

0

Chyba zaczynam rozumieć, zapewne muszę trochę po praktykować, żeby lepiej to ogarnąć.

Ostatnie pytanie w takim razie Shalom " Klasa określa typ obiektu i tylko w wyjątkowych sytuacjach określa jakąś "czynność". Czynności zwykle są metodami/funkcjami, a u ciebie wszystko jest klasą o_O" - Nie rozumiem.

Myślałem, że klasa jest szablonem, na którym piszemy metody/funkcje.

Jeżeli klasa określa jedynie typ obiektu, to weźmy przykład: Kot - je śpi i coś jeszcze.

Określając typ obiektu, klasa to musiał by być "zwierzak", a metody je(), śpi(), coś_jeszcze().

Jeżeli tak by to wyglądało, to jak by wyglądała klasa zwierzak? Chodzi mi o to, jak praktycznie w javie miałby wyglądać taki kod do "kota", żeby klasa była klasą a metoda metodą, a nie jak mnie to wychodzi all inclusive?

0

Jak nie ma powodu, by robić dziedziczenie, to się dziedziczenia nie robi. W Twoim przypadku byłaby więc klasa kot i metody je(), śpi(), budzi_człowieka_o_czwartej_nad_ranem(). Klasy zwierzak by wcale nie było, bo nie jest do niczego potrzebna.

Byłaby, jakbyś miał więcej różnych gatunków zwierząt. Wtedy możliwości są dwie. Albo czynności wykonywane przez te zwierzęta są implementacyjnie takie same, więc tworzysz klasę zwierzak, która je()śpi() i dziedziczysz po niej kota, który dodatkowo budzi_człowieka_o_czwartej_nad_ranem()psa, który zjada_buty(). Albo, jeśli tak nie jest, to interfejs/klasę abstrakcyjną.

0

Jednak nie ostatnie pytanie. ;)

Jeśli tak, to wygląda, to czym różniłaby się klasa abstrakcyjna od interfejsu?

Po klasie abstrakcyjnej, pomniejsze klasy dziedziczyły by zwierzęta jako obiekty, a interfejs byłby szablonem pod codzienne czynności, które by wykonywały?

0

Interfejs jest bardziej abstrakcyjny od klasy abstrakcyjnej :).

Klasa abstrakcyjna to taka klasa, która nie ma instancji — tworzy się ją, żeby po niej dziedziczyć i mieć pewną abstrakcję co do konkretów. Tzn. jeśli wykorzystujesz tylko elementy klasy bazowej, to możesz podstawić dowolny z typów pochodnych, nie przejmując się szczegółami.
Interfejs natomiast to natomiast klasa abstrakcyjna całkowicie pozbawiona konkretów. On tylko mówi, że coś ma zostać zaimplementowane (więc obiecuje, że wszystkie klasy go realizujące będą miały odpowiednie pola, metody itd.), ale nie mówi jak.

Rozróżnienie nie jest zresztą wspólne dla wszystkich języków. Główna różnica sprowadza się do tego, że w pewnych językach (Java, PHP) klasa może implementować dowolną liczbę interfejsów, ale mieć tylko jedną klasę, po której dziedziczy. Wówczas interfejsy opisują bardziej jaka jest klasa, jakie ma własności (np. czy da się porównywać jej instancje, czy jest kontenerem itd.), a klasa bazowa (bez znaczenia abstrakcyjna czy nie) mówi czym jest klasa.
No ale to nie we wszystkich językach, w takim na przykład C++ czy Pythonie jest dziedziczenie wielobazowe (czyli klasa może dziedziczyć po wielu klasach), co czyni to całe rozróżnienie nonsensownym. Ja się, prawdę mówiąc, lepiej odnajduję w czymś takim.

0

Dzięki za pomoc, trochę poszperałem, troch rozjaśniło mi to sprawę.

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