This shows you the differences between two versions of the page.
poo-ca-cd:arhiva:laboratoare:2023:visitor [2024/10/05 20:49] alexandru.olteanu created |
poo-ca-cd:arhiva:laboratoare:2023:visitor [2024/11/10 16:53] (current) silvia_elena.nistor |
||
---|---|---|---|
Line 1: | Line 1: | ||
- | ===== Laboratorul 7: Overriding, overloading & Visitor pattern ===== | + | ===== Laboratorul 7: Visitor pattern ===== |
**Video introductiv:** [[https://www.youtube.com/watch?v=_mfLYYInv6c| link ]] | **Video introductiv:** [[https://www.youtube.com/watch?v=_mfLYYInv6c| link ]] | ||
Line 5: | Line 5: | ||
==== Obiective ==== | ==== Obiective ==== | ||
- | * Implementarea polimorfismului în Java | ||
- | * Diferența dintre Overriding & Overloading | ||
* Prezentarea design pattern-ului Visitor și familiarizarea cu situațiile în care acesta este util de aplicat | * Prezentarea design pattern-ului Visitor și familiarizarea cu situațiile în care acesta este util de aplicat | ||
- | |||
- | ==== Polimorfismul ==== | ||
- | |||
- | **Polimorfismul reprezintă abilitatea unei clase să se comporte ca o altă clasă de pe lanțul de moștenire, și de aceea conceptul de suprascriere a metodelor este foarte strâns legat.** | ||
- | |||
- | Mai precis, polimorfismul permite obiectelor de tipuri diferite să fie tratate folosind o interfață comună sau o clasă de bază. | ||
- | Există două tipuri principale de polimorfism în POO: polimorfismul prin suprascrierea metodelor (override) și polimorfismul prin supraincarcarea metodelor (overloading). | ||
- | |||
- | ==== Overriding ==== | ||
- | |||
- | **Suprascrierea** se referă la redefinirea metodelor existente în clasa părinte de către clasa copil în vederea specializării acestora. | ||
- | |||
- | * Metodele din clasa parinte nu sunt modificate. | ||
- | * Putem suprascrie doar metodele vizibile pe lanțul de moștenire (public, protected). | ||
- | * O metodă din clasa copil suprascrie metoda din clasa părinte dacă are **același tip de return** și **aceeași semnatură**. | ||
- | |||
- | <note important> **Semnătura (signature)** unei metode constă în: | ||
- | * numele metodei | ||
- | * numărul și tipul parametrilor | ||
- | </note> | ||
- | |||
- | În cazul suprascrierii se determină ce metodă va fi apelată, în mod dinamic, **la runtime**. Explicația este că decizia se face pe baza __tipului obiectului__ care apelează metoda, deci a instanței, care e cunoscută la runtime. | ||
- | Din acest motiv, suprascrierea este cunoscută și ca **polimorfism dinamic** (__Runtime polymorphism__). | ||
- | |||
- | |||
- | <note important> La apelarea unei metode suprascrise, Java se uită la tipul intern al obiectului pentru care este apelată metoda, NU la referință. Astfel dacă referința are tipul clasei părinte, dar tipul obiectului este al clasei copil, JVM va apela metoda din clasa copil. </note> | ||
- | |||
- | Câteva **reguli pentru suprascriere** sunt: | ||
- | * metoda suprascrisă are același tip de return și semnatură ca metoda inițială | ||
- | * putem avea un tip de return diferit de cel al metodei inițiale, atâta timp cat este un tip ce moștenește tipul de return al metodei inițiale | ||
- | * specificatorul de access al metodei suprascrise nu poate fi mai restrictiv decât cel al metodei inițiale | ||
- | * nu poate arunca mai multe excepții sau excepții mai generale, poate însă arunca mai puține sau mai particulare sau excepții unchecked (de runtime) | ||
- | * metodele de tip ''static'' și ''final'' nu pot fi suprascrise | ||
- | * constructorii nu pot fi suprascriși | ||
- | |||
- | În exemplul de mai jos, metodele //purr// și //getFeatures// au fost suprascrise de tipul //GrumpyCat//. | ||
- | <code java> | ||
- | class CatFeatures { } | ||
- | class GrumpyCatFeatures extends CatFeatures { } | ||
- | class GrumpyFeatures { } | ||
- | |||
- | class Cat { | ||
- | |||
- | public void purr() { | ||
- | System.out.println("purrrr"); | ||
- | } | ||
- | |||
- | public CatFeatures getFeatures() { | ||
- | System.out.println("Cat getFeatures"); | ||
- | return new CatFeatures(); | ||
- | } | ||
- | |||
- | public final void die() { | ||
- | System.out.println("Dying! frown emoticon"); | ||
- | } | ||
- | } | ||
- | |||
- | class GrumpyCat extends Cat { | ||
- | @Override | ||
- | public void purr() { | ||
- | System.out.println("NO!"); | ||
- | } | ||
- | |||
- | @Override | ||
- | public GrumpyCatFeatures getFeatures() { | ||
- | System.out.println("Grumpy getFeatures"); | ||
- | return new GrumpyCatFeatures(); | ||
- | } | ||
- | |||
- | // compiler would complain if you included @Override here | ||
- | //@Override | ||
- | //public void die() { } // Cannot override the final method from Cat | ||
- | |||
- | public static void main(String [] args) { | ||
- | ArrayList<Cat> cats = new ArrayList<Cat>(); | ||
- | cats.add(new Cat()); | ||
- | cats.add(new GrumpyCat()); | ||
- | |||
- | for (Cat c : cats) { | ||
- | c.purr(); | ||
- | c.die(); | ||
- | c.getFeatures(); | ||
- | } | ||
- | } | ||
- | } | ||
- | |||
- | </code> | ||
- | |||
- | |||
- | <note important>**Adnotarea** (**Annotation**) ''@Override'' este complet opțională. Totuși este indicat să o includeți mereu când suprascrieți o metodă. | ||
- | Motivele sunt simple: | ||
- | * Compilatorul vă va anunța printr-o eroare dacă ați greșit numele metodei sau tipul parametrilor și această nouă metodă nu suprascrie de fapt o metodă a părintelui | ||
- | * Face codul vostru mai ușor de citit, pentru că devine evident când o metodă suprascrie o altă metodă | ||
- | </note> | ||
- | |||
- | <note tip> | ||
- | O metodă cu argumente de tip primitiv nu poate fi suprascrisă cu o metodă cu tip wrapper. | ||
- | |||
- | ''public void doSmth(int x)'' nu poate fi suprascrisă cu ''public void doSmth(Integer x)'' | ||
- | |||
- | Metoda cu argument de tip wrapper poate primi si null, insă cea cu tipul primitiv nu, de aceea, neputând să fie păstrată echivalența, nu este permisă aceasta suprascriere | ||
- | |||
- | </note> | ||
- | |||
- | |||
- | ==== Overloading ==== | ||
- | |||
- | **Supraîncarcarea** se referă la posibilitatea de a avea într-o clasă mai multe metode cu același nume, dar implementari diferite. În Java, compilatorul poate distinge între metode pe baza semnăturii lor, acesta fiind mecanismul din spatele supraîncărcarii. | ||
- | |||
- | Opțional, pe lângă semnătura metodei poate fi menționat și tipul excepțiilor ce pot fi aruncate din codul acesteia. | ||
- | |||
- | <note important> | ||
- | Tipul de return al unei metode NU face parte din semnătura acesteia. Din acest motiv simpla modificare a tipului de return al unei metode nu este suficientă pentru supraîncărcare. Ceea ce vom primi este o eroare de compilare. | ||
- | <code java> | ||
- | public class TRex { | ||
- | public void eat(Triceratops victim) { | ||
- | System.out.println("Take 5 huge bites"); | ||
- | } | ||
- | | ||
- | public boolean eat(Triceratops victim) { | ||
- | boolean satisfaction = false; | ||
- | if (victim.isJuicy()) { | ||
- | System.out.println("Eat and be satisfied"); | ||
- | satisfaction = true; | ||
- | } | ||
- | return satisfaction; | ||
- | } | ||
- | | ||
- | // Error "Duplicate method eat(Triceratops)" in type TRex | ||
- | </code> | ||
- | Observăm de asemenea că la compilare nu se ține cont de numele dat parametrilor. Astfel modificarea acestuia din //victim// în //dino//, spre exemplu, nu constituie o supraîncărcare validă. | ||
- | </note> | ||
- | |||
- | * O clasă poate supraîncărca metodele moștenite. | ||
- | * Constructorii pot fi supraîncărcați. | ||
- | |||
- | Spre deosebire de suprascriere, **supraîncărcarea are loc la compilare**, motiv pentru care mai este numită și **polimorfism static** (__compile time polymorphism__). În aceasta fază compilatorul decide ce metodă este apelată pe baza __tipului referinței__ și prin analiza numelui și a listei de parametri. La runtime, când este întalnit apelul unei metode supraîncărcate, deja se știe unde este codul care trebuie executat. | ||
- | |||
- | Mai jos avem un exemplu valid de supraîncărcare pentru metoda // eat//: | ||
- | <code java> | ||
- | public class TRex { | ||
- | | ||
- | public void eat(Triceratops victim) { | ||
- | System.out.println("Take 5 huge bites"); | ||
- | } | ||
- | | ||
- | public void eat(Dromaeosaurus victim) { // parametru cu tip diferit | ||
- | System.out.println("Take 1 single bite"); | ||
- | } | ||
- | | ||
- | public void eat(Human firstCourse, Human secondCourse) { // numar si tipuri diferite de parametrii | ||
- | System.out.println("No humans to eat at the time"); | ||
- | } | ||
- | | ||
- | public int eat(Grass desert) { // parametru cu tip diferit, return type este irelevant | ||
- | System.out.println("Rather starve"); | ||
- | return 0; | ||
- | } | ||
- | |||
- | public static void main(String [] args) { | ||
- | TRex john = new TRex(); | ||
- | | ||
- | john.eat(new Triceratops()); // "Take 5 huge bites" | ||
- | john.eat(new Dromaeosaurus()); // "Take 1 single bite" | ||
- | john.eat(new Human("Ana"), new Human("Andrei")); // "No humans to eat at the time" | ||
- | john.eat(new Grass()); // "Rather starve" | ||
- | } | ||
- | } | ||
- | </code> | ||
==== Visitor Design Pattern ==== | ==== Visitor Design Pattern ==== | ||
Line 421: | Line 250: | ||
==== Summary ==== | ==== Summary ==== | ||
- | |||
- | {{:poo-ca-cd:laboratoare:lab7.png?600|}} | ||
- | |||
**Visitor** = behavioral design pattern | **Visitor** = behavioral design pattern | ||
Line 450: | Line 276: | ||
==== Referințe ==== | ==== Referințe ==== | ||
- | - Kathy Sierra, Bert Bates. //SCJP Sun Certified Programmer for Java™ 6 - Study Guide//. Chapter 2 - Object Orientation ([[http://firozstar.tripod.com/_darksiderg.pdf|available online]]) - moștenire, polimorfism, overriding, overloading + exemple de întrebări | ||
- Vlissides, John, et al. //Design patterns: Elements of reusable object-oriented software//. Addison-Wesley (1995) ([[http://index-of.co.uk/Software-Engineering/Design%20Patterns%20-%20Elements%20Of%20Reusable%20Object-Oriented%20Software%20-%20Addison%20Wesley.pdf|available online]]) | - Vlissides, John, et al. //Design patterns: Elements of reusable object-oriented software//. Addison-Wesley (1995) ([[http://index-of.co.uk/Software-Engineering/Design%20Patterns%20-%20Elements%20Of%20Reusable%20Object-Oriented%20Software%20-%20Addison%20Wesley.pdf|available online]]) | ||
- [[http://en.wikipedia.org/wiki/Software_design_pattern | Clasificarea design pattern-urilor]] | - [[http://en.wikipedia.org/wiki/Software_design_pattern | Clasificarea design pattern-urilor]] |