Come rappresentare le implementazioni auto-composte nelle gerarchie di ereditarietà

0

Background: la mia azienda sta lavorando con i sistemi di telecamere. All'inizio abbiamo costruito la nostra applicazione attorno a diversi modelli / configurazioni di essi, che consistevano in diverse macchine fotografiche o procedure per acquisire e combinare i dati acquisiti. Tuttavia, eravamo sempre limitati ad avere un singolo sistema attivo nella nostra applicazione. Un giorno abbiamo avuto l'idea di collegare più sistemi di telecamere per acquisire più dati contemporaneamente in periodi di tempo più brevi. Da allora, abbiamo problemi a rappresentarlo in modo pulito nel nostro software.

Concettualmente abbiamo questo design molto semplificato:

class ICamSystem
{}

class SomeCamSystemImpl : public ICamSystem
{}

class MultiCamSystem
{
  std::vector<ICamSystem> cam_systems;
}

La grande decisione è se dobbiamo o meno avere MultiCamSystem derivare e implementare ICamSystem. A prima vista questo sembra molto ragionevole perché in teoria un MultiCamSystem dovrebbe supportare praticamente lo stesso insieme di operazioni di ICamSystem. In effetti, la maggior parte delle implementazioni di MultiCamSystem fa semplicemente inoltrare una chiamata di metodo a tutti i suoi sistemi di telecamere composite. Decidere contro questo significa anche che dovremmo gonfiare ogni singolo sito di chiamata con una distinzione di casi tra avere un singolo sistema di telecamere o un sistema di telecamere multiple. D'altra parte, seguendo il Principio di sostituzione di Liskov un MultiCamSystem non è un ICamSystem e ha portato a tutti i tipi di problemi di follow-up. Due esempi molto semplici:

ICamSystem::set_parameter

ha un'implementazione molto naturale per un sistema di telecamere: o riesce e imposta il parametro o fallisce con un'eccezione. Su un sistema a più telecamere vorrei intuitivamente implementarlo in questo modo:

MultiCamSystem::set_parameter( const Param& p )
{
  for(auto* cs : cam_systems)
    cs->set_parameter(p)
}

Ma in alcuni casi questo non ha senso perché ogni sistema di telecamere potrebbe avere intervalli diversi di parametri validi / accettabili. Ad esempio, l'impostazione dell'esposizione in questo modo molto probabilmente non ha molto senso perché, a causa delle condizioni di illuminazione esterne, devo spesso regolarle singolarmente per ciascun sistema, il che rompe la mia astrazione dall'avere un singolo sistema di telecamere che accetta un singolo tempo di esposizione. Devo anche preoccuparmi della gestione degli errori, ad esempio quando un'operazione fallisce su un sottoinsieme dei sistemi di telecamere.

Data ICamSystem::acquire_data() or
SystemID ICamSystem::getID()

Prima, avevo solo un singolo valore di ritorno da un metodo. Con un sistema multi-camera questo deve essere piuttosto:

std::vector<Data> ICamSystem::acquire_data() or
std::vector<SystemID> ICamSystem::getID()

così di nuovo questo rompe la mia astrazione. Ovviamente potrei cambiare la firma nell'interfaccia astratta e fare in modo che i singoli sistemi di telecamere restituiscano un vettore di dimensione 1. Ma sembra sconsigliabile mettere a punto un'interfaccia generica e perfettamente ragionevole per implementazioni specifiche di esso.

Quale è un modo migliore per rappresentarlo allora?

    
posta user1709708 09.08.2017 - 17:56
fonte

1 risposta

3

Una collezione di X non è necessariamente essa stessa una X. A volte una raccolta di X è proprio questa; altre volte, è probabilmente più spesso un manager di X (con alcune responsabilità di gestione orientate al dominio) piuttosto che funzionare come una sola X stessa (anche se non sarebbe inaudito essere sia un manager di X che una X stessa) .

Tuttavia, in questo caso, il gruppo di fotocamere semplicemente non è esso stesso una fotocamera.

Deciding against this also means we would have to bloat every single call site with a distinction of cases between having a single ... or a multi ...

Questo è un costo trascurabile, IMHO. (Tuttavia, se è pratico per te, puoi implementare solo il multi, e poi avvolgere una singola X in una raccolta, se necessario, per utilizzare le multi-routine.)

    
risposta data 09.08.2017 - 19:08
fonte

Leggi altre domande sui tag