360 likes | 456 Views
Koncept generali z acije klasa i metoda. Od tipa / klase Object nasleđuju sve klase u .NET Framework-u, kao i korisničke klase
E N D
Konceptgeneralizacije klasa i metoda • Od tipa / klase Object nasleđuju sve klase u .NET Framework-u, kao i korisničke klase • Samim tim tip Object pruža mogućnost da se kao parametar tipa Object prenese bilo koji vrednosni ili referentni tip ili da se kao povratna vrednost tipa Object može vratiti bilo koji tip • Takva mogućnost je veoma korisno upotrebljena kod klasa tipa kolekcija – ArrayList, Queue, Stack, Hashtable, SortedList koje su jedna vrsta generalizacije klasičnih nizova kod kojih elementi kolekcije mogu biti bilo kog tipa, jer su tipa Object
Klasa Queue • Klasa System.Collections.Queuemože da sardži elemente bilo kog tipa • using System.Collections; • ... • Queue myQueue = new Queue(); • Circle myCircle = new Circle(); • myQueue.Enqueue(myCircle); • ... • myCircle = (Circle)myQueue.Dequeue(); • public void Enqueue( object item ); • public object Dequeue();
Klasa Queue • Na osnovu deklaracije metoda Enqueue i Dequeue vidi se da objekti mogu biti bilo kog tipa / klase, jer je argument Enqueue tipa Object, a povratni tip Dequeue takođe Object • Ono što tu nije dobro, je da je neophodno da se radi type cast da bi se moglo pristupiti podacima raznih tipova koji su preneti kao objekti • Ako se napravi greška pri type cast-u, onda se takva greška ne otkriva u toku kompajliranja, već u run time-u, samim tim takve greške se teže otkrivaju • To značajno umanjuje sve prednosti koje se dobijaju korišćenjem tipa Object za prenos podataka raznih tipova
Klasa Queue • Queue myQueue = new Queue(); • Circle myCircle = new Circle(); • myQueue.Enqueue(myCircle); • ... • Clock myClock = (Clock)myQueue.Dequeue(); // run-time error • Queue myQueue = new Queue(); • int myInt = 99; • myQueue.Enqueue(myInt); // box the int to an object • ... • myInt = (int)myQueue.Dequeue(); // unbox the object to an int
Prenos vrednosnih tipova • Pri prenosu vrednosnih tipova, kao što je int, preko tipa Object, vrši se boxing (konverzija u referentni tip) i unboxing (vraćanje u vrednosni tip) • Ove operacije dodatno angažuju resurse računara i mogu da dovedu do usporenja, pogotovo ako se radi o velikom broju podataka
Generički tipovi • Generički tipovi su uvedeni u C# da bi se pojednostavilo kreiranje i rad sa generičkim klasama i metodima, zatim da bi se poboljšala bezbednost, otklonile potrebe za type casting-om, kao i nepotrebni box-ing i unbox-ing • Generičke klase i metode imaju tipizirane parametre, tj. omogućavaju tipiziranje parametara • .NET Framework uključuje generičke verzije raznih vrsta klasa i interfejsa u imenskom prostoru System.Collections.Generic
Generički tipovi • using System.Collections.Generic; • ... • Queue<Circle> myQueue = new Queue<Circle>(); • Circle myCircle = new Circle(); • myQueue.Enqueue(myCircle); • ... • myCircle = myQueue.Dequeue(); • Unutar uglastih zagrada <> se nalazi tip parametara • Nije potreban type cast kada se koristi metod Dequeue, samim tim se i ne vrši box-ing i unbox-ing
Generički tipovi • Navođenje tipova parametara između uglastih zagrada omogućava da se naznače tipovi koji se očekuju, pa zbog toga type cast nije potreban • Samim tim se greške kod tipova parametara otkrivaju još u fazi prevođenja • Definicija generic Queue class i metoda: • public class Queue<T> : ... • public void Enqueue( T item ); • public T Dequeue(); • T predstavlja tip parametra – placeholder za stvarni tip parametra koji će zameniti T
Generički tipovi • Stvarni tip parametra koji će zameniti T svuda u definiciji klase se navodi kada se deklariše kolekcija Queue u programu • Treba naglasiti da je ova zamena T sa konkretnim tipom mnogo više od proste zamene teksta, jer kompajler vrši potpunu semantičku zamenu, svuda gde se u definiciji generičke klase koristi tip T, tako da se može navesti bilo koji validni tip – vrednosni, klasa ili struktura
Generički tipovi • struct Person • { • ... • } • ... • Queue<int> intQueue = new Queue<int>(); • Queue<Person> personQueue = new Queue<Person>(); • Queue<Queue<int>> queueQueue = new Queue<Queue<int>>(); • public void Enqueue( int item ); • public int Dequeue();
class Dictionary • Klasa System.Collections.Generic.Dictionaryje primer klase sa dva generička parametra za ključ Tkey i vrednost TValue • public class Dictionary<TKey, TValue> • Moguć je i pristup vrednostima korišćenjem sintakse kao sa indeksom, ali gde se zaista koriste vrednosti ključeva • public virtual TValue this[ TKey key ] { get; set; }
class Dictionary • struct Person • { • ... • } • ... • Dictionary<string, Person> directory = new Dictionary<string, Person>(); • Person john = new Person(); • directory[“John”] = john; • ... • Person author = directory[“John”];
Generičke i generalisane klase • Klasa System.Collections.Queue je generalisana klasa koja može da prihvati parametre - elemente bilo kog tipa • Nezavisno od tipa elemenata kolekcije Queue u konkretnom slučaju, uvek se radi o jednoj istoj implementaciji klase i svi metodi uzimaju parametre tipa Object i vraćaju vrednosti tipa Object • Za razliku od toga, kada se koristi System.Collections.Generic.Queue<T>klasa, kompajler generiše potpuno novu klasu za izabrani tip podataka. Funkcionalnost te nove klase je određena generičkom klasom koja predstavlja šablon za izgradnju klase sa odabranim tipom podataka
Ograničenja kod generičkih klasa • Kod generičkih klasa se mogu koristiti ograničenja u smislu da li klasa parametra poseduje, tj. Implementira neke neophodne funkcionalnosti koje se zahtevaju od svih tipova parametara • Takva ograničenja se jednostavno mogu uvesti preko interface-a • public class PrintableCollection<T> where T : IPrintable • Ako IPrintable interface deklariše metod Print, onda će kompajler pre kreiranja klase sa odabranim tipom proveriti da li taj tip implementira zahtevani metod
The System.IComparable and System.IComparable<T> Interfaces • Interface IComparable deklariše metod CompareTo koji uzima jedan argument tipa object, poredi ga sa tekućom vrednošću i vraća integer -1, 0 i 1 u zavisnosti od rezultata poređenja • public int CompareTo(Object obj) • IComparable<T> interface deklariše dva metoda za poređenje objekata određenog tipa • int CompareTo(T other); • bool Equals(T other);
Poređenje objekata • Value Meaning • Less than 0: The current instance is less than the value of the parameter. • 0: The current instance is equal to the value of the parameter. • Greater than 0: The current instance is greater than the value of the parameter
class Circle • { • public Circle(int initialRadius) • { • radius = initialRadius; • } • public double Area() • { • return Math.PI * radius * radius; • } • private double radius; • }
class Circle : System.IComparable • { • ... • public int CompareTo(object obj) • { • Circle circObj = (Circle)obj; // cast the parameter to its real type • if (this.Area() == circObj.Area()) • return 0; • if (this.Area() > circObj.Area()) • return 1; • return -1; • } • }
class Circle : System.IComparable<Circle> • { • ... • public int CompareTo(Circle other) • { • if (this.Area() == other.Area()) • return 0; • if (this.Area() > other.Area()) • return 1; • return -1; • }
Generički interfejs • public bool Equals(Circle other) • { • return (this.CompareTo(other) == 0); • } • }
Generički metodi • Slično generičkim klasama, mogu se kreirati i generički metodi • Generički metodi mogu imati parametre i povratne vrednosti tipova koji ne moraju biti određeni već samo naznačeni sa place holder-om pri deklaraciji, ali koji se navode pri deklaraciji klase čiji su to metodi static void Swap<T>(ref T first, ref T second) { T temp = first; first = second; second = temp; }
Poziv generičkih metoda • int a = 1, b = 2; • Swap<int>(ref a, ref b); • ... • string s1 = “Hello”, s2 = “World”; • Swap<string>(ref s1, ref s2); • Analogno kao što se deklaracijom klase na osnovu generičke klase kreira nova klasa na osnovu izabranih tipova parametara, pri svakom pozivu generičkih metoda sa konkretnim tipom parametara kreira novi metod na osnovu generičkog za odabrani tip parametara
Binary Trees - primer • Binarno drvo je rekurzivna samoreferencirajuća struktura podataka koja sadrži tri podatka – korisni podatak u tekućem čvoru i dve reference ka dve podstrukture tipa drveta – levo i desno poddrvo • Binarno drvo se može koristiti za jednostavno sortiranje i pretragu podataka • Drvo je struktura koja se može teoretski jednostavno neograničeno produžavati
Algoritam za dodavanje elemenata • If the tree, T, is empty • Then • Construct a new tree T with the new item I as the node, and empty left and • right subtrees • Else • Examine the value of the current node, N, of the tree, T • If the value of N is greater than that of the new item, I • Then • If the left subtree of T is empty • Then • Construct a new left subtree of T with the item I as the node, and • empty left and right subtrees • Else • Insert I into the left subtree of T • End If • Else • If the right subtree of T is empty • Then • Construct a new right subtree of T with the item I as the node, and • empty left and right subtrees • Else • Insert I into the right subtree of T • End If • End If • End If
Algoritam za pregled elemenata • If the left subtree is not empty • Then • Display the contents of the left subtree • End If • Display the value of the node • If the right subtree is not empty • Then • Display the contents of the right subtree • End If
Implementacija binarnog drveta • namespace BinaryTree • { • public class Tree<TItem> where TItem : IComparable<TItem> • { • public Tree(TItem nodeValue) • { • this.NodeData = nodeValue; • this.LeftTree = null; • this.RightTree = null; • } • public TItem NodeData { get; set; } • public Tree<TItem> LeftTree { get; set; } • public Tree<TItem> RightTree { get; set; }
public void Insert(TItem newItem) • { • TItem currentNodeValue = this.NodeData; • if (currentNodeValue.CompareTo(newItem) > 0) • { • if (this.LeftTree == null) • { • this.LeftTree = new Tree<TItem>(newItem); • } • else • { • this.LeftTree.Insert(newItem); • } • } • else • { • if (this.RightTree == null) • { • this.RightTree = new Tree<TItem>(newItem); • } • else • { • this.RightTree.Insert(newItem); • } • } • }
public void WalkTree() • { • if (this.LeftTree != null) • { • this.LeftTree.WalkTree(); • } • Console.WriteLine(this.NodeData.ToString()); • if (this.RightTree != null) • { • this.RightTree.WalkTree(); • } • }
class Program • { • static void Main(string[] args) • { • Tree<int> tree1 = new Tree<int>(10); • tree1.Insert(5); • tree1.Insert(11); • tree1.Insert(5); • tree1.Insert(-12); • tree1.Insert(15); • tree1.Insert(0); • tree1.Insert(14); • tree1.Insert(-8); • tree1.Insert(10); • tree1.Insert(8); • tree1.Insert(8); • tree1.WalkTree();
Tree<string> tree2 = new Tree<string>("Hello"); • tree2.Insert("World"); • tree2.Insert("How"); • tree2.Insert("Are"); • tree2.Insert("You"); • tree2.Insert("Today"); • tree2.Insert("I"); • tree2.Insert("Hope"); • tree2.Insert("You"); • tree2.Insert("Are"); • tree2.Insert("Feeling"); • tree2.Insert("Well"); • tree2.Insert("!"); • tree2.WalkTree();