Java - dedicnost a interface
Dedicnost a interface si ukazeme na priklade, ktory predstavuje uzivatela a informacny system.
Uzivatel sa prihlasuje do IS pomocou svojho id a hesla. IS potom rozhodne, ci daneho
uzivatela prihlasi alebo nie. Uvazme nasledujucich uzivatelov:
- Administrator
- Teacher
- Student
A IS bude mat metodu login, ktora bude mat ako parametre nejake id uzivatela a jeho heslo.
Tato metoda zaroven vrati logicku hodnotu true, ak sa jedna o opravneneho uzovatela, v opacnom
pripade vrati false.
Dedicnost
Najprv si ukazeme ako by sme riesili tuto ulohu najhlupejsim sposobom. A to tak ze vytvorime
pre kazdeho uzivatela odpovedajucu triedu:
public class Administrator {
private int id;
private String name;
private String password;
public Administrator(long id, String name, String password) {
this.id = id;
this.name = name;
this.password = password;
}
public int getId() {
return id;
}
public String getName() {
return name;
}
public void setPassword(String password) {
this.password = password;
}
// + nejake metody, ktore sluzia na administraciu IS
}
public class Student {
private int id;
private String name;
private String password;
public Student(int id, String name, String password) {
this.id = id;
this.name = name;
this.password = password;
}
public int getId() {
return id;
}
public String getName() {
return name;
}
public void setPassword(String password) {
this.password = password;
}
// + nejake metody, ktore sluzia na prihlasovanie predmetov
}
public class Teacher {
private int id;
private String name;
private String password;
public Teacher(int id, String name, String password) {
this.id = id;
this.name = name;
this.password = password;
}
public int getId() {
return id;
}
public String getName() {
return name;
}
public void setPassword(String password) {
this.password = password;
}
// + nejake metody, ktorym ucitel moze zadavat do ISu nove predmety
}
A nas informacny system by vyzeral nasledujuco
public class InformationSystem {
public boolean login(Administrator admin, String password) {
// podla toho ako je IS implementovany rozhodne ci uzivatela prihlasi
}
public boolean login(Teacher teacher, String password) {
// podla toho ako je IS implementovany rozhodne ci uzivatela prihlasi
}
public boolean login(Student student, String password) {
// podla toho ako je IS implementovany rozhodne ci uzivatela prihlasi
}
}
Prve coho si vsimneme je, ze triedy Administrator, Teacher a Student maju vela spolocneho.
Taktiez implementacia triedy InformationSystem je velmi stupidna, pretoze pre kazdeho
uzivatela je zvlast metoda. Predstavte si, ze budeme chciet aby nas IS umoznil pristup
este aj inym uzivatelom, to by sme zase museli pridat novu metodu login :(
Vychodiskom je prave dedicnost, t.j. vytiahneme z tried Administrator, Teacher a Student
vlastnosti, ktore maju vsetci spolocne a vytvorime triedu User
public class User {
private int id;
private String name;
private String password;
public User(int id, String name, String password) {
this.id = id;
this.name = name;
this.password = password;
}
public int getId() {
return id;
}
public String getName() {
return name;
}
public void setPassword(String password) {
this.password = password;
}
}
A triedy Administrator, Teacher a Student budu iba rozsirovat triedu User.
Na rozsirovanie (dedenie) sa pouziva klucove slovo extends, takze nase
triedy budu vyzerat takto
public class Administrator extends User {
public Administrator(int id, String name, String password) {
super(id, name, password);
}
// + nejake metody, ktore sluzia na administraciu IS
// napr. metody createNewUser(), removeUser() a pod.
}
public class Teacher extends User {
public Teacher(int id, String name, String password) {
super(id, name, password);
}
// + nejake metody, ktore sluzia na administraciu IS
// napr. metody createNewCourse(), inputMarks() a pod.
}
public class Student extends User {
public Student(int id, String name, String password) {
super(id, name, password);
}
// + nejake metody, ktore sluzia na administraciu IS
// napr. metody enrollInCourse(), enrollForExam() a pod.
}
A nasa trieda InformationSystem bude vyzerat nasledujuco
public class InformationSystem {
public boolean login(User user, String password) {
// podla toho ako je IS implementovany rozhodne ci uzivatela prihlasi
}
}
Takato implementacia je uz ovela prehladnejsia a rozumnejsia. Vsimnite si ze metoda
login uz bere ako parameter instanciu triedy User, avsak zobere aj dalsie instancie tried,
ktore su potomkami (dedia, rozsiruju) triedy User. Treba spomenut, ze Java nepodporuje
viacnasobnu dedicnost, to znamena, ze nejaka trieda moze vzdy rozirovat maximalne
1 triedu (ale rozhrani moze implementovat kolko len chce). Tiez si vsimnite klucoveho
slova super, ktore znamena, ze sa odkazujeme na rodicovsku triedu. V nasom
pripade volame rodicovsky konstruktor.
Doteraz sme sa stretli s viditelnostami atributov a metod iba private a public.
Pri dedicnosti sa casto pouziva viditelnost protected, co znamena, ze
dany atribut/metodu mozeme upravovat/prekryvat aj z potomkov nasej danej triedy.
Tak ako mame tento nas priklad, tak viditelnost atributu password v triede User je
private a preto v triede Administrator nemozeme nijako sa odkazovat na tento atribut.
Ak vsak zmenime tuto vididelnost na protected (v triede User), tak v triede
Administrator mozeme s tymto atributom veselo manipulovat. V pripade protected
metody mozeme v potomkoch tuto metodu prekryt. To znamena, ze si mozeme napisat
vlastny kod tejto metody, avsak metoda musi zachovat rovnaky nazov, rovnaky pocet parametrov a
ich typy a tiez musi vratit rovnaky typ.
Interface
Dalej si este ukazeme priklad na interface. Zatial sme nikde neuviedli na zaklade coho
nas informacny system rozhodne, ci uzivatela prihlasi alebo nie. To naznacuje, ze
uzivatela ani moc nezaujima ako je to v ISe implementovane, ale ake metody musi uzivatel
pouzit aby sa prihlasil, preto vytvorime interface pre IS.
public interface InformationSystem {
boolean login(User user, String passowrd);
}
A vytvorime si nasledujuce informacne systemy
Tieto informacne systemy budu implementovat rozhranie InformationSystem, t.j. musia
mat metodu login. Vsimnite si ze v rozhrani nie je uvedena viditelnost tejto metody,
avsak pri konkretnej implementacii budeme pouzivat viditelnost public.
public class StupidIS implements InformationSystem {
public boolean login(User user, String password) {
return true;
}
}
StupidIS vzdy prihlasi kazdeho uzivatela.
public class NormalIS implements InformationSystem {
private String[] passwords;
public NormalIS() {
passwords = new String[3];
passwords[0] = "admin";
passwords[1] = "abc123";
passwords[2] = "pa$$word";
}
public boolean login(User user, String password) {
if(user.getId() >= passwords.length) {
return false;
}
return passwords[user.getId()].equals(password);
}
}
NormalIS uz ma v sebe ulozene nejake hesla pomocou ktorych kontroluje prihlasujuceho uzivatela.
Teraz este upravime triedu User tak, ze pridame novu metodu
public boolean login(InformationSystem is) {
return is.login(this, password);
}
Vsimnite si, ze tato metoda bere ako paramter InformationSystem,
teda vsetky instancie, ktore implementuju toto rozhranie. Z toho vyplyva, ze vzdy
ked trieda implementuje rozhranie, definujte jej typ pomocou rozhrania. Podobne,
i ked nie v takej miere, plati aj pre dedicnost.
Dalsie poznamky najdete v komentaroch v prilozenom projekte Demo.