Interface eksponerer type A, men gjennomføringen krever type B (underklasse av A)

stemmer
0

Jeg har et system som jeg har blitt bryting med for en stund. I hovedsak bruker det mye av abstraksjon å håndtere det faktum at senere utvidelse er ikke bare forventet, men nødvendig. Ett sted dette kreves er tilgang til data. Systemet generelt omhandler administrerende gjenstander innkapsle noen observasjon (i betydningen av en observert verdi eller et sett av verdier) og bruke dem. For å oppnå dette, jeg har noe til effekten av:

public interface Observation 
{
    /** UniqueKey is used to access/identify an observation */
    UniqueKey Key
    {
        get;
    }
}

public interface ObservationDataSource
{
    /** 
      * Retrieves an Observation from the actual data source.
      * performs any necessary operations to encapsulate values in object
      */
    Observation GetObservationByUniqueKey(UniqueKey key);
}

Problemet oppstår for spesifikke implementeringer av disse grensesnittene. Til slutt, Observationog ObservationDataSourceer klassen implementeres med spesifikke runtime klasser. Imidlertid UniqueKeykan også utvides til å håndtere uansett unikt identifiserer sett av verdier er for en observasjon i datakilden (kanskje en id, kanskje en gang, etc). Så eventuell gjennomføring av GetObservationByUniqueKeyvil utsette et UniqueKeyargument, men forventer en bestemt underklasse. Jeg forventer UniqueKeyå bli avgitt til en bestemt type gang vedtatt i.

Dette virker som en dårlig design valg, siden gjennomføringen lyver om argumentet krav - men jeg kan ikke se en annen måte å gjøre dette. Jeg forventer at andre skal være å bruke disse grensesnittene, så jeg kan ikke bare si at jeg kommer til å huske denne konvensjonen.

Noen ideer til å fikse det, eller håndtere det mer elegant?

Publisert på 09/04/2009 klokken 23:23
kilden bruker
På andre språk...                            


3 svar

stemmer
0

Jeg er ikke sikker på om dette er hva du vil, men det virker for meg at du kan prøve å gjøre det med generics:

public interface Observation<T> where T : UniqueKey
{
    T Key { get; }
}

public interface ObservationDataSource<T> where T : UniqueKey
{
    Observation<T> GetObservationByUniqueKey(T key);
}

Nå grensesnittet er sterkt skrevet med den spesifikke underklasse av UniqueKey at klassen krever.

Svarte 09/04/2009 kl. 23:45
kilden bruker

stemmer
0

Jeg ser ikke dette som et problem, bare ved å endre denne uttalelsen av deg:

Så noen implementering av GetObservationByUniqueKey vil utsette en UniqueKey argument, men forventer en bestemt underklasse hvis og bare hvis det UniqueKey ble generert av denne ObservationDataSource .

Hvis UniqueKey er ikke av den forventede typen, det er bare en triviell avvisning sak som kan håndteres på to måter:

(1) Ved å utsette en UniqueKeyType eiendom i ObservationDataSource grensesnitt, kan den som ringer av GetObservationByUniqueKey sjekke UniqueKey Instans skriver a priori.

(2) Det blir de kontraktsmessige ansvar for hver GetObservationByUniqueKey implementor for å håndtere det tilfelle hvor UniqueKey ikke ble generert av den. (Dette virker helt rimelig for meg)

Men hele problemet ber spørsmålet - hvorfor er du tillater UniqueKey å være polymorfe i første omgang, når du allerede har en definert oppslag funksjon for å få på dataobjekter?

Svarte 10/04/2009 kl. 00:29
kilden bruker

stemmer
0

Du sier

Så noen implementering av GetObservationByUniqueKey vil utsette en UniqueKey argument,

Howerver, dette er feil. Det vil ikke utsette argument - det vil få en. Som du sier, kan den som ringer passere vilkår unike nøkler, og det er ingenting galt med det.

For en bestemt datakilde, vil bare bestemte unike nøkler har knyttet observasjon - ikke bare bestemt wrt. type, men også spesifikke wrt. til virkelig verdi. Hvis verdien har ingen observasjon forbundet, returnerer du null (antar jeg). Gjør det samme hvis type UNIQUEID er feil - hvis noen passerer en tid da en ID er forvente, ingen observasjon er assosiert med denne nøkkelen, i den datakilden.

OTOH, hvis den som ringer er fri til å plukke unike IDer, og datakilden er ment å returnere en tom observasjon å bli fylt av den som ringer, så har du to valg:

  1. Ikke bruk grensesnitt i første omgang. Angivelig, kan du ikke erstatte en implementering for den andre, og den som ringer må være klar over hva implementering de bruker.
  2. Alternativt, sørg for at alle implementasjoner støtter alle typer unike nøkler.
Svarte 10/04/2009 kl. 15:09
kilden bruker

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more