Devo essere in grado di adattare il mio tipo al loro e il loro al mio

7

Ho una situazione in cui ho una libreria esterna. In breve, ho bisogno di essere in grado di adattare il mio tipo al loro e il loro al mio. La libreria ha una raccolta come questa:

interface IExternalCollection
{
    void Add(IExternal item);
    IExternal Get(int index);
}

Ora, iniziamo spiegando la soluzione semplice più . Ho un adattatore normale per questa raccolta e adattatori regolari per IExternal e IInternal:

interface IInternalCollection
{
    void Add(IInternal item);
    IInternal Get(int index);
}

class InternalCollectionAdapter : IInternalCollection
{
    private IExternalCollection collection;

    public InternalCollectionAdapter(IExternalCollection collection)
    {
        this.collection = collection;
    }

    public void Add(IInternal item)
    {
        collection.Add(new ExternalAdapter(item));
    }

    public IInternal Get(int index)
    {
        return new InternalAdapter(collection.Get(index));
    }
}

Questa soluzione richiede 2 adattatori per lo stesso tipo e il mio ExternalAdapter adatta InternalAdapter (non esiste un tipo concreto interno). Quel che è peggio è che la mia interfaccia interna ha solo 2 metodi, ma l'interfaccia esterna ha molti (15-ish). Nel mio codice, ho solo bisogno di questi 2, motivo per cui ho progettato la mia interfaccia per avere solo quelli 2, ma ora ho bisogno di raggruppare la mia interfaccia con tutti e 15 per poter creare ExternalAdapter .

Quindi ho pensato, sicuramente c'è un modo migliore. Ho letto su 2WayAdapter e ha il seguente aspetto:

class TwoWayAdapter : External, IInternal
{
    public void Show()
    {
        base.Display();
    }     
}

Questo mi permette di scrivere un CollectionAdapter in questo modo:

class InternalCollectionAdapter : IInternalCollection
{
    private IExternalCollection collection;

    public InternalCollectionAdapter(IExternalCollection collection)
    {
        this.collection = collection;
    }

    public void Add(IInternal item)
    {
        collection.Add((IExternal)item);
    }

    public IInternal Get(int index)
    {
        return (TwoWayAdapter)collection.Get(index);
    }
}

E chiamalo così:

collection.Add(new TwoWayAdapter()); 
collection.Get(0);

Funziona, e ho solo bisogno di 1 adattatore per il tipo, e posso progettare la sua API come mi pare.

Tuttavia, questa libreria esterna crea i propri oggetti di tipo Esterno . Pertanto, quando chiamo Get sulla raccolta esterna, è possibile che venga restituita un'istanza di recente aggiunta di Esterno , rendendo impossibile eseguire il cast su TwoWayAdapter .

La mia ultima soluzione è consentire l'accesso a adaptee , come questo:

class InternalAdapter : IInternal
{
    private IExternal adaptee;
    public Object Adaptee { get { return adaptee; } }

    public InternalAdapter(IExternal adaptee)
    {
        this.adaptee = adaptee;
    }

    public void Show()
    {
        adaptee.Display();
    }
}

Ciò cambierà il mio CollectionAdapter in questo modo:

class InternalCollectionAdapter : IInternalCollection
{
    private IExternalCollection collection;

    public InternalCollectionAdapter(IExternalCollection collection)
    {
        this.collection = collection;
    }

    public void Add(IInternal item)
    {
        collection.Add((IExternal)item.Adaptee);
    }

    public IInternal Get(int index)
    {
        return new InternalAdapter(collection.Get(index));
    }
}

Come puoi vedere, questo richiede che la mia interfaccia interna abbia una proprietà Object Adaptee { get; } , che ha un odore davvero molto cattivo.

Posso solo immaginare che questa situazione sia venuta fuori molte volte, ma i miei sforzi su Internet sono stati vani.

Vorrei una soluzione in cui posso mantenere pulita la mia API da tutti i metodi esterni di cui non ho bisogno e preferibilmente una in cui Adaptee rimane nascosto.

Modifica

Dopo aver riflettuto un po 'di più su questo problema, ho trovato una soluzione che sembra all'altezza delle mie esigenze, vale a dire un'API pulita che non include elementi di cui non ho bisogno e che non espone il < strong> adaptee .

Is è una combinazione delle mie precedenti iterazioni e va come follews:

  • Per adattare il loro tipo al mio, utilizzo un adattatore regolare

    class InternalAdapter : IInternal
    {
        private IExternal adaptee;
    
        public InternalAdapter(IExternal adaptee)
        {
            this.adaptee = adaptee;
        }
    
        public void Show()
        {
            adaptee.Display();
        }
    }
    
  • Per adattare questo tipo alla loro, creo un TwoWayAdapter .

    class TwoWayAdapter : External, IInternal
    {
        public void Show()
        {
            base.Display();
        }     
    }
    
  • Quindi il mio CollectorAdapter ha il seguente aspetto:

    class InternalCollectionAdapter : IInternalCollection
    {
        private IExternalCollection collection;
    
        public InternalCollectionAdapter(IExternalCollection collection)
        {
            this.collection = collection;
        }
    
        public void Add(IInternal item)
        {
            collection.Add((IExternal)item);
        }
    
        public IInternal Get(int index)
        {
            return new InternalAdapter(collection.Get(index));
        }
    }
    

Ora potresti notare che questa soluzione ha i suoi problemi, vale a dire, non posso get uno dei loro tipi, quindi convertirla in miniera, riconvertirla e add nella loro raccolta.

Questa soluzione funziona nel mio caso in questo progetto solo perché get recupera una nuova istanza e add è usata solo con una nuova istanza (aggiunta da me), cioè lo stesso oggetto non è getted e added .

Il motivo per cui ho reso questo un edit e non una risposta è che, questo non risolve il problema più generale che propongo in questa domanda.

Solo per chiarire quello che sto chiedendo: Mi piacerebbe conoscere articoli, blog o libri che risolvano questo problema con una tecnica o un modello. Mi piacerebbe anche che qualcuno potesse fare riferimento a ciò che hanno fatto in situazioni precedenti.

    
posta Chris Wohlert 10.06.2016 - 15:01
fonte

1 risposta

1

Recentemente sono diventato un grande fan degli stili di programmazione funzionale. Ecco una demo su come iniziare a lavorare su questo, nota che non ho compilato o inserito il codice in Visual Studio. Se porti avanti questa idea, penso che tu abbia solo bisogno di altri due metodi per andare dall'altra parte! Se avessi più tempo, proverei a utilizzare anche Generics per ridurre la codifica del 50%.

public static class XAdapters{
   public static IExternalCollection AsExternalCollection(this InternalCollection intneralCollection) where Q:new(){
        var externalCollection = new ExternalCollection();
        inputCollection.ToList().ForEach(input=>{
           //create output item is an extenion method too
           output.Add(input.CreateNewOutputItem());
       }
       return externalCollection;
   }

  public static IExternalCollection Add(this IExternalCollection externalCollection, InternalCollectionItem item){

    var x =  item.CreateNewExternalItem();
    externalCollection.Add(x);
    return externalCollection;
   }

}

Per utilizzare il codice sopra:

var externalCollection = InternalCollection.AsExternalCollection.Add(someInternalItem);

Ecco i convertitori di fabbrica:

public static extneralItem createNewExtneralItem(this intneralItem internal)          {
     var extern = new externalItem();
     extern.property = internal.property; //etc...
     return extern;
}
    
risposta data 18.06.2016 - 04:18
fonte

Leggi altre domande sui tag