Kako ne koristiti sučelja u C #

Prilikom dizajniranja aplikacije često ćete trebati koristiti sučelja i apstraktne klase. Ovaj članak raspravlja o nekim uobičajenim primjerima "zlouporabe sučelja" i strategijama koje možemo koristiti da bismo ih izbjegli. Također se raspravlja o tome što se podrazumijeva pod načelom, "program na sučelje, a ne na implementaciju".

Što su sučelja?

Prvo, shvatimo sučelja i zašto su potrebna u programiranju. Sučelje je strogo ugovor; nema nikakve provedbe. Sučelje sadrži samo deklaracije članova. Možete imati deklaracije metoda, ali ne i definicije. Članovi deklarirani u sučelju trebaju se implementirati u tipove (klase i strukture) koji proširuju ili implementiraju sučelje. Sučelje ne može sadržavati polja. Sučelje se ne može serijalizirati jer ne može imati članove podataka. Kao što sam rekao, sučelje može imati samo deklaracije, a ne i definicije.  

Izbjegavajte promjene na sučeljima 

Klasa ili struktura koja proširuje sučelje trebala bi implementirati sve svoje članove. Ako se implementacija promijeni, vaš će kôd i dalje raditi. Međutim, ako se ugovor, odnosno sučelje promijeni, morat ćete promijeniti implementacije svih vrsta koje proširuju sučelje. Drugim riječima, svaka promjena sučelja utjecati će na sve vrste koje proširuju sučelje. Tipovi koji proširuju sučelje moraju se pridržavati ugovora. Dakle, koristite sučelja samo kada ih rijetko trebate mijenjati. Također, općenito je bolje stvoriti novo sučelje nego mijenjati postojeće. 

Program na sučelje, a ne na implementaciju

Možda ste povremeno čuli riječi "programirati na sučelje, a ne na implementaciju". Možda ste koristili sučelja u svom kodu, ali još uvijek ste programirali implementaciju. Ispitajmo sada razliku između ta dva pristupa.

Kada programirate na sučelje, koristite konkretnu apstrakciju (sučelje ili apstraktnu klasu) umjesto konkretne implementacije. Budući da sučelja jamče jednoobraznost, programiranje sučelja podrazumijeva da možete rukovati sličnim objektima na jednolik način. Pritom ste odvojeni od implementacije - tj. Vaše implementacije mogu se razlikovati. To dodaje fleksibilnost i vašim dizajnom.

Sljedeći isječak koda ilustrira programiranje sučelja. Razmotrimo sučelje nazvano IRepository koje sadrži izjavu nekoliko metoda. Klase ProductRepository i CustomerRepository proširuju sučelje IRepository i implementiraju metode deklarirane u IRepository sučelju, kao što je prikazano u nastavku.

javno sučelje IRepository

    {

        // Neki kod

    }

    javna klasa ProductRepository: IRepository

    {

        // Neki kod

    }

    javna klasa CustomerRepository: IRepository

    {

        // Neki kod

    }

Sljedeći se kôd može koristiti za stvaranje instance ProductRepositorija.

Repozitorij IRepository = novo ProductRepository ();

Ideja je da ovdje možete koristiti bilo koju klasu koja implementira sučelje IRepository. Dakle, valjana je i sljedeća izjava.

Repozitorij IRepositorija = novi CustomerRepository ();

Kada programirate implementaciju, ta se jednolikost gubi. Umjesto toga, obično ćete imati neke konstrukcije, kao što su "if..else" ili "switch..case", za kontrolu ponašanja u vašem kodu.

Izbjegavajte prekomjernu upotrebu sučelja

Povezivanje svakog razreda sa sučeljem nije dobra praksa. Prekomjerna upotreba sučelja na ovaj način stvara nepotrebnu složenost, uvodi suvišnost koda, krši YAGNI i smanjuje čitljivost i održivost baze koda. Sučelja se koriste za grupiranje objekata koji imaju identično ponašanje. Ako objekti nemaju identično ponašanje, nema potrebe za ovim grupiranjem. Korištenje sučelja kada nećete imati višestruku implementaciju primjer je pretjerane upotrebe sučelja.

Stvaranje sučelja za klasu koje odgovara javnim članovima klase prilično je često. Pritom uopće ne dodajete nikakvu vrijednost - samo duplicirate sučelje klase bez dodavanja stvarne apstrakcije.

Pogledajmo sada primjer kako se sučelja prekomjerno koriste. Razmotrite sljedeće sučelje nazvano IProduct.

javno sučelje IPproduct

    {

        int Id {get; postavljen; }

        string ProductName {get; postavljen; }

        dvostruka cijena {get; postavljen; }

        int Količina {get; postavljen; }

    }

Klasa proizvoda proširuje sučelje IProduct kako je prikazano u nastavku.

javna klasa Proizvod: IPprodukt

    {

        javni int Id {get; postavljen; }

        javni niz ProductName {get; postavljen; }

        javna dvostruka cijena {get; postavljen; }

        public int Količina {get; postavljen; }

    }

Jasno je da nam ne treba sučelje IProduct jer su sučelje i njegova implementacija identični. Suvišni kod je nepotreban.

Pogledajmo još jedan primjer. Sljedeći isječak koda prikazuje sučelje pod nazivom IProductManager koje ima deklaraciju dviju metoda, naime Spremi i Ažuriraj.

 javno sučelje IProductManager

    {

        void Spremi (proizvod IPproduct);

        poništenje ažuriranja (proizvod IPproduct);

    }

Sučelje IProductManager sadrži deklaracije javnih metoda klase ProductManager. Evo kako izgleda klasa ProductManager.

 javna klasa ProductManager: IProductManager

    {

        javna praznina Spremi (proizvod IPproduct)

        {

           // Ovdje napišite svoju implementaciju

        }

        javno void ažuriranje (proizvod IPproduct)

        {

            // Ovdje napišite svoju implementaciju

        }

    }

Sučelja IProduct i IProductManager primjeri su pretjerane upotrebe sučelja. Oba ova sučelja imaju jednu implementaciju i uopće ne dodaju nikakvu vrijednost.

Korištenjem sučelja možete ukloniti nepotrebne spojnice u kodu i učiniti svoj kod lako provjerljivim. Međutim, treba izbjegavati prekomjernu upotrebu sučelja. Koristite sučelja samo kada će ih biti više od jedne implementacije. Sučelja možete koristiti i kada imate klasu koja ima mnogo uloga ili koja ima višestruku odgovornost. U ovom slučaju vaša klasa može implementirati više sučelja - po jedno za svaku ulogu.