Impossibile decidere un modello di progettazione appropriato

2

Non riesco a trovare un design (pattern) per un'applicazione / servizio che colpirà più servizi web (API esterne di terze parti), analizzeremo, combineremo e restituiremo in un'unica risposta.

L'applicazione avrà i seguenti comportamenti / passaggi (in nessun ordine particolare):

  • Cerca hotel
  • Recupera i dettagli dell'hotel selezionato
  • Recupera i dettagli della camera dell'hotel selezionato
  • Recupera criteri di cancellazione
  • Carica addebiti extra per i clienti
  • Blocca la room room del libro
  • Ottieni i dettagli della camera prenotata
  • Annulla la sala prenotata

Non tutte le API avranno / implementeranno i passaggi precedenti. Ad esempio, poche API potrebbero non avere il 3 ° passaggio o il 4 ° passaggio o entrambi. In breve, i passaggi / la combinazione di passaggi possono cambiare in base al provider dell'API.

Una volta avviata una ricerca per hotel dall'applicazione Web, la richiesta verrà inviata a questa applicazione. Recupera quindi tutti i provider API attivi (interfaccia C # comune) dal database e invia la richiesta a ciascuna API. Voglio esporre un'interfaccia comune durante l'istanziazione delle classi del fornitore. La stessa metodologia verrà seguita per ogni passaggio.

Sto cercando di pensare a un modello di design e di progettare una soluzione che rispetti i principi SOLID. Sulla base del requisito di cui sopra, ho pensato ai seguenti schemi ma finora non ho avuto successo:

  1. Metodo di produzione: definire un'interfaccia comune con tutto quanto sopra passaggi / comportamenti e utilizzare il metodo di fabbrica per creare l'oggetto (s). Tuttavia, questo porterà alla violazione della sostituzione di Liskov principio poiché alcune API potrebbero non implementare tutto.
  2. Motivo decoratore: definisce un componente (interfaccia) che conterrà i passaggi comuni. Aggiungi passaggi / comportamento in modo dinamico usando decoratore. Tuttavia, con questo design, l'interfaccia del componente non avrà alcuna conoscenza dei passaggi / comportamenti aggiunti che vanificano il nostro scopo di utilizzare un'interfaccia comune.

C'è qualche altro modello che è l'ideale per il mio problema o dovrei andare avanti con la prima soluzione e vivere con la violazione principale?

Esempio di codice per aiutare a chiarire il problema (nessun modello seguito, inteso a chiarire gli attori coinvolti):

public interface IAPIProvider
{
    void SearchHotels();
    void GetHotelDetails();
    void GetRoomDetails();
    void GetCancellationPolicies();
    void GetExtraGuestChargeDetails();
    void BlockRoom();
    void BookRoom();
    void GetBookingDetails();
    void CancelBooking();
}


public class ConcreteProviderA : IAPIProvider
{
    public void BlockRoom()
    {
        //call api
    }

    public void BookRoom()
    {
        //call api
    }

    public void CancelBooking()
    {
        //call api
    }

    public void GetBookingDetails()
    {
        //call api
    }

    public void GetCancellationPolicies()
    {
        //call api
    }

    public void GetExtraGuestChargeDetails()
    {
        //call api
    }

    public void GetHotelDetails()
    {
        //call api
    }

    public void GetRoomDetails()
    {
        //call api
    }

    public void SearchHotels()
    {
        //call api
    }
}

public class ConcreteProviderB : IAPIProvider
{
    public void BlockRoom()
    {
        throw new NotImplementedException();
    }

    public void BookRoom()
    {
        //call api
    }

    public void CancelBooking()
    {
        //call api
    }

    public void GetBookingDetails()
    {
        //call api
    }

    public void GetCancellationPolicies()
    {
        throw new NotImplementedException();
    }

    public void GetExtraGuestChargeDetails()
    {
        throw new NotImplementedException();
    }

    public void GetHotelDetails()
    {
        //call api
    }

    public void GetRoomDetails()
    {
        //call api
    }

    public void SearchHotels()
    {
        //call api
    }
}

/// <summary>
/// Request from web/mobile will land in this class
/// </summary>
public class Client
{
    public void SearchHotel()
    {
        //get active providers from database & instantiate them
        List<IAPIProvider> providers = new List<IAPIProvider>();            
        foreach(var provider in providers)
        {
            //search hotels from each API provider
            provider.SearchHotels();
        }
    }

    public void GetHotelDetails(int hotelId, int hotelProviderId)
    {
        IAPIProvider provider = null;

        //here, resolve the correct API provider using the input parameters            

        //fetch hotel details from the resolved API provider
        provider.GetHotelDetails();
    }

    //Other methods
}

Esempio di codice come aspetto .

    
posta Sang Suantak 02.06.2017 - 11:23
fonte

4 risposte

3

Puoi utilizzare il modello Adattatore per creare un wrapper per ciascuna API di terze parti.
Questi wrapper forniranno tutti la stessa interfaccia al resto della tua applicazione e dovrebbero implementare un comportamento predefinito corretto per le operazioni che l'API di terze parti non supporta.

    
risposta data 02.06.2017 - 11:39
fonte
0

Osservando la tua obiezione al modello di fabbrica, mi sembra che potresti usare il modello di strategia in cui puoi perfezionare la funzionalità di cui hai bisogno.

    
risposta data 02.06.2017 - 11:35
fonte
0

Se vuoi avere una soluzione orientata agli oggetti (ho il sospetto che sia per questo che vuoi conformarti a SOLID), e hai già i casi d'uso che hai menzionato sopra, continua con l'identificazione delle "cose" che vuoi coinvolgere . Ad esempio:

  • Albergo
  • Camera
  • Prenotazione (di una stanza)
  • Politica di cancellazione
  • ecc.

Non iniziare a implementare direttamente i casi d'uso, il che risulterebbe in una progettazione procedurale (probabilmente l'opposto dell'orientamento agli oggetti). Prova a scomporre i casi d'uso in un comportamento che le tue "cose" potrebbero fare per te. Ad esempio:

  • Room.reserve (): Reservation
  • Reservation.cancel (): ...
  • ...

Vorrei anche aggiungere Hotel.display() e metodi simili invece di Hotel.getRooms() (che porta a Legge di Demeter violazioni), ma questo è un po 'controverso.

Questo ti darà un "modello", che puoi implementare usando chiamate remote, servizi web o quant'altro.

Quindi, suggerirei di iniziare con un design "buono" (con oggetti che significano qualcosa e fare cose), concentrarsi meno sui "modelli di progettazione".

    
risposta data 02.06.2017 - 12:35
fonte
0

Mi sembra che il tuo esempio di codice stia andando nella giusta direzione così com'è, pattern o non.

Se si desidera definire un'interfaccia comune per tutte le API di terze parti, non c'è niente di sbagliato nel dire "le le API dovrebbero avere queste capacità" e quindi gestire i casi in cui non lo sono.

Indipendentemente da ciò, dovrai tenere conto di quando le azioni che prevedi si verifichino. Come se provassi a prenotare una stanza, ma è troppo tardi perché qualcun altro l'ha bloccato prima. O se l'API di terze parti si interrompe per qualche motivo, o raggiungi un limite di velocità sulle loro API, o la rete va giù, ecc. Quindi non vedo nulla di sbagliato nell'aggiungere qualche gestione degli errori personalizzata se le API non lo fanno esistono per determinati metodi. Il tuo codice sembra buono.

    
risposta data 02.06.2017 - 13:47
fonte

Leggi altre domande sui tag