Programmering

Hvordan ikke bruke grensesnitt i C #

Når du designer et program, må du ofte bruke grensesnitt og abstrakte klasser. Denne artikkelen drøfter noen vanlige eksempler på "grensesnittmisbruk" og strategiene vi kan bruke for å unngå dem. Den diskuterer også hva som menes med prinsippet, "program til et grensesnitt og ikke til en implementering."

Hva er grensesnitt?

Først og fremst, la oss få en forståelse av grensesnitt og hvorfor de er nødvendige for programmering. Et grensesnitt er strengt tatt en kontrakt; den har ingen implementering. Et grensesnitt inneholder bare medlemserklæringer. Du kan ha metodedeklarasjoner, men ikke definisjoner. Medlemmene som er erklært i et grensesnitt, bør implementeres i de typene (klasser og strukturer) som utvider eller implementerer grensesnittet. Et grensesnitt kan ikke inneholde felt. Et grensesnitt kan ikke serialiseres fordi det ikke kan ha data-medlemmer. Som sagt kan et grensesnitt bare ha erklæringer og ikke definisjoner.

Unngå å gjøre endringer i grensesnittene

En klasse eller en struktur som utvider et grensesnitt, bør implementere alle medlemmene. Hvis implementeringen endres, vil koden din fortsatt fungere. Men hvis kontrakten, dvs. grensesnittet, endres, må du endre implementeringene av alle typer som utvider grensesnittet. Med andre ord, enhver endring i grensesnittet vil påvirke alle typene som utvider grensesnittet. Typene som utvider grensesnittet, må overholde kontrakten. Så bruk grensesnitt bare når du sjelden trenger å endre dem. Det er også generelt bedre å lage et nytt grensesnitt enn å endre et eksisterende.

Programmer til et grensesnitt, ikke til en implementering

Du har kanskje hørt ordene "programmer til et grensesnitt og ikke til en implementering" nå og da. Du har kanskje brukt grensesnitt i koden din, men du programmerte fremdeles til implementeringen. La oss nå undersøke forskjellen mellom de to tilnærmingene.

Når du programmerer til et grensesnitt, bruker du den mest generiske abstraksjonen (et grensesnitt eller en abstrakt klasse) i stedet for en konkret implementering. Siden grensesnitt garanterer ensartethet, innebærer programmering til et grensesnitt at du kan håndtere lignende objekter på en enhetlig måte. Når du gjør det, er du frakoblet implementeringen - dvs. implementeringene dine kan variere. Dette gir også fleksibilitet til designene dine.

Følgende kodebit illustrerer programmering til et grensesnitt. Vurder et grensesnitt som heter IRepository som inneholder erklæringen om noen få metoder. Klasserne ProductRepository og CustomerRepository utvider IRepository-grensesnittet og implementerer metodene som er angitt i IRepository-grensesnittet, som vist nedenfor.

offentlig grensesnitt IRepository

    {

// Noe kode

    }

offentlig klasse ProductRepository: IRepository

    {

// Noe kode

    }

offentlig klasse CustomerRepository: IRepository

    {

// Noe kode

    }

Følgende kode kan brukes til å opprette en forekomst av ProductRepository.

IR-depot = nytt ProductRepository ();

Tanken er at du kan bruke hvilken som helst klasse her som implementerer IRepository-grensesnittet. Så følgende påstand er også gyldig.

IRepository repository = nytt CustomerRepository ();

Når du programmerer til en implementering, går denne ensartetheten tapt. I stedet vil du vanligvis ha noen konstruksjoner, for eksempel "if..else" eller "switch..case" -uttalelser, for å kontrollere oppførselen i koden din.

Unngå overbruk av grensesnitt

Å knytte hver klasse til et grensesnitt er ikke god praksis. Overbruk av grensesnitt på denne måten skaper unødvendig kompleksitet, introduserer redundans av kode, bryter med YAGNI og reduserer lesbarheten og vedlikeholdbarheten til kodebasen. Grensesnitt brukes til å gruppere sammen objekter som har identisk oppførsel. Hvis objektene ikke har identisk oppførsel, er det ikke behov for denne grupperingen. Å bruke grensesnitt når du ikke skal ha flere implementeringer av det, er et eksempel på overbruk av grensesnitt.

Å lage et grensesnitt for en klasse som samsvarer med de offentlige medlemmene i klassen, er ganske vanlig. Når du gjør det, legger du ikke til noen verdi i det hele tatt - du dupliserer bare grensesnittet til klassen uten å legge til noen reell abstraksjon.

La oss nå se på et eksempel på hvordan grensesnitt blir brukt for mye. Vurder følgende grensesnitt som heter IProduct.

offentlig grensesnitt IProduct

    {

int Id {get; sett; }

streng Produktnavn {get; sett; }

dobbel pris {get; sett; }

int Mengde {get; sett; }

    }

Produktklassen utvider IP-produktgrensesnittet som vist nedenfor.

offentlig klasse Produkt: IProduct

    {

offentlig int Id {get; sett; }

offentlig streng Produktnavn {get; sett; }

offentlig dobbelt Pris {get; sett; }

offentlig int Mengde {get; sett; }

    }

Det er klart at vi ikke trenger IProduct-grensesnittet, da grensesnittet og implementeringen av det er identisk. Den overflødige koden er unødvendig.

La oss se på et annet eksempel. Følgende kodebit viser et grensesnitt kalt IProductManager som har deklarasjonen av to metoder, nemlig Lagre og oppdater.

 offentlig grensesnitt IProductManager

    {

void Save (IProduktprodukt);

ugyldig oppdatering (IProduktprodukt);

    }

IProductManager-grensesnittet inneholder erklæringer om de offentlige metodene i ProductManager-klassen. Slik ser ProductManager-klassen ut.

 offentlig klasse ProductManager: IProductManager

    {

offentlig ugyldig Lagre (IProduktprodukt)

        {

// Skriv implementeringen din her

        }

offentlig ugyldig oppdatering (IProduktprodukt)

        {

// Skriv implementeringen din her

        }

    }

Grensesnittene IProduct og IProductManager er eksempler på overbruk av grensesnittet. Begge disse grensesnittene har en enkelt implementering, og de gir ingen verdi i det hele tatt.

Ved å bruke grensesnitt kan du fjerne unødvendige koblinger i koden din og gjøre koden din lett testbar. Imidlertid bør overbruk av grensesnitt unngås. Bruk bare grensesnitt når det vil være mer enn én implementering av dem. Du kan også bruke grensesnitt når du har en klasse som har mange roller å spille eller som har flere ansvarsområder. I dette tilfellet kan klassen implementere flere grensesnitt - ett for hver rolle.

$config[zx-auto] not found$config[zx-overlay] not found