Interfejs ti je kao ugovor. On definiše metode,
property-e, itd. koje svaka klasa mora da implementira ako implementira i taj interfejs. Evo jedan primer iz prakse.
Definišeš interfejs za snimanje objekta
Student u bazu podataka.
Code:
public interface IStudentRepository
{
Student GetById(int id);
List<Student> GetAll();
void Save(Student student);
void Delete(int id);
}
I sada hoćeš da napraviš konkretnu implementaciju tog interfejsa koja će da koristi EntityFramework za rad sa bazom:
Code:
public class StudentRepositoryEntityFramework : IStudentRepository
{
public Student GetById(int id)
{
// insert some code here
}
public List<Student> GetAll()
{
// insert some code here
}
public void Save(Student student)
{
if (student.Id > 0)
Update(student);
else
Create(student);
}
private void Create(Student student)
{
// insert some code here
}
private void Update(Student student)
{
// insert some code here
}
public void Delete(int id)
{
// insert some code here
}
}
Klasa
StudentRepositoryEntityFramework je sklopila ugovor sa interfejsom
IStudentRepository. To znači da mora da implementira sve metode koje su definisane u interfejsu
IStudentRepository i te metode moraju biti
public.
Save metoda ne može biti
private, internal ili protected, ona
mora biti public. Tvoja konkretna implementacija može da sadrži i neke metode koje nisu definisane u interfejsu, kao što su
Create, Update, itd., ali sve metode koje su definisane u interfejsu moraju biti implementirane i moraju biti
public, ok?
Interfejsi se najviše koriste kod
Dependency injection i
Inversion of control pattern-a. Dosta je komplikovano u početku da se skapira, ali poenta je sledeća:
Sve što radiš, radiš sa interfejsima, a ne sa konkretnim implementacijama. Zašto?
1. Zbog Unit Testova. Implementaciju možeš uvek da zameniš sa nekim
fake objektom.
2. Ako želiš da promeniš implementaciju, tj. nećeš više da koristiš EntityFramework već NHibernate. Ako na 50 mesta u kodu koristiš
StudentRepositoryEntityFramework umesto
IStudentRepository, onda ćeš na tih 50 mesta morati da zameniš
StudentRepositoryEntityFramework sa
StudentRepositoryNHibernate. Ako na 50 mesta u kodu koristiš
IStudentRepository, onda ćeš izmenu morati da napraviš samo na jednom mestu (na mestu gde se definiše koja klasa se instancira za dati interfejs)!
Citat:
darthskywalker:Koliko sam primjetio da bi uporedili dva objekta, klasa mora implementirati interface. Zasto bi klasa implementirala interfejs da bi se mogla uporediti dva objekta, zasto jednostavno bez interfejsa se ne napravi metod koji ce uporedjivati objekte?
Recimo da smo definisali 3 klase:
Code:
public class Honda
{
public string Model { get; set; }
}
public class Porsche
{
public string Model { get; set; }
}
public class Boeing
{
public string Model { get; set; }
}
Ono što hoćemo da uradimo jeste da napravimo konzolnu aplikaciju koja će iz liste nekih objekata da prepozna koji objekti su automobili i da ispiše njihove modele:
Code:
internal class Program
{
public static void Main(string[] args)
{
var allItems = new List<object>
{
new Honda { Model = "Civic" },
new Porsche { Model = "Porsche 911" },
new Boeing { Model = "747" }
};
DisplayCarModels(allItems);
}
private static void DisplayCarModels(IEnumerable<object> items)
{
foreach (var item in items)
{
if (item is Honda)
Console.WriteLine(((Honda)item).Model);
else if (item is Porsche)
Console.WriteLine(((Porsche)item).Model);
}
}
}
Rezultat:
Code:
Civic
Porsche 911
Primetićeš da u metodi
DisplayCarModels smo morali da ispitujemo da li je objekat odeređenog tipa i da ga
cast-ujemo u taj tip kako bismo dobili vrednost
Model property-a. Ovde ne samo da ima malo više za kucanje, već se i narušava
open / closed principle koji je jedan od SOLID principa
http://en.wikipedia.org/wiki/Solid_(object-oriented_design) (neki ih smatraju i svetim gralom objektno orjentisanog programiranja :) ).
Šta to zapravo znači?
Ako kreiraš novu klasu
Ferrari, moraćeš da promeniš i metodu
DisplayCarModels koja treba da ispita da li je objekat tipa
Ferrari.
Kako da rešimo ovo? Primenom interfejsa :)
Honda i
Porsche će implementirati interfejs
ICar, a
Boeing neće.
Definišemo novi interfejs
Code:
public interface ICar
{
string Model { get; set; }
}
Sklopimo ugovor između klasa i interfejsa
Code:
public class Honda : ICar
{
public string Model { get; set; }
}
public class Porsche : ICar
{
public string Model { get; set; }
}
public class Boeing
{
public string Model { get; set; }
}
Napravimo izmenu u
DisplayCarModels metodi.
Code:
internal class Program
{
public static void Main(string[] args)
{
var allItems = new List<object>
{
new Honda { Model = "Civic" },
new Porsche { Model = "Porsche 911" },
new Boeing { Model = "747" }
};
DisplayCarModels(allItems);
}
private static void DisplayCarModels(IEnumerable<object> items)
{
foreach (var item in items)
{
if (item is ICar)
Console.WriteLine(((ICar)item).Model);
}
}
}
Rezultat:
Code:
Civic
Porsche 911
U metodi
DisplayCarModels ispitujemo da li objekat ima sklopljen ugovor sa
ICar interfejsom jer on sadrži ono što nama treba. Ne zanima nas da li objekat pored modela sadrži još neki
propery ili metodu...
Ako dodamo novu klasu Ferrari koja implementira interfejs ICar, metoda DisplayCarModels će raditi bez ikakvih modifikacija:
Code:
internal class Program
{
public static void Main(string[] args)
{
var allItems = new List<object>
{
new Honda { Model = "Civic" },
new Porsche { Model = "Porsche 911" },
new Boeing { Model = "747" },
new Ferrari { Model = "Enzo" }
};
DisplayCarModels(allItems);
}
private static void DisplayCarModels(IEnumerable<object> items)
{
foreach (var item in items)
{
if (item is ICar)
Console.WriteLine(((ICar)item).Model);
}
}
}
Rezultat:
Code:
Civic
Porsche 911
Enzo
[Ovu poruku je menjao Dejan Carić dana 24.06.2012. u 20:54 GMT+1]