Metodi sovraccaricati e argomenti opzionali - questo è un cattivo schema da seguire?

1

Sto creando un'interfaccia per registrare la cronologia di navigazione.

Per prima cosa, abbiamo tre tipi di record: Registrabile (il comportamento predefinito), Revisibile (un utente può guardare la loro cronologia e rivisitare quell'elemento), e Traversibile (l'utente può semplicemente "tornare indietro"). I record traversibili sono, per definizione, Revisibili che sono, a loro volta, registrabili. Questi tipi sono codificati in un enum.

Ogni record contiene le informazioni necessarie per ripristinare la vista in uno stato particolare. Il nostro design è modulare e basato su azioni: alcune azioni prendono dei parametri. Quindi, la cronologia deve registrare il modulo e l'azione al minimo - e talvolta i parametri di azione, e talvolta il recordType (se non il default), e talvolta entrambi.

Questo mi porta a:

void recordAction(const QString &moduleName, const QString &actionName);
void recordAction(const QString &moduleName, const QString &actionName, QVariantMap parameters);
void recordAction(const QString &moduleName, const QString &actionName, QVariantMap parameters, int recordType);
void recordAction(const QString &moduleName, const QString &actionName, int recordType);

Questo è un buon modello? O dovrei implementare qualcosa di più:

void recordAction(const QString &moduleName, const QString &actionName, QVariantMap parameters = QVariantMap());
void recordRevisitableAction(const QString &moduleName, const QString &actionName, QVariantMap parameters = QVariantMap());
void recordTraversibleAction(const QString &moduleName, const QString &actionName, QVariantMap parameters = QVariantMap());

Suppongo che, in definitiva, questi metodi chiameranno semplicemente un interno:

void recordAction(const QString &moduleName, const QString &actionName, QVariantMap parameters, int recordType);

Quindi, qual è il modello migliore da seguire? Anche se non vedo ancora un'esigenza, potrebbe esserci un altro tipo di record a cui non ho pensato ...

    
posta HorusKol 05.05.2017 - 02:32
fonte

2 risposte

7

Inizia sempre con leggibilità . Dal punto di vista di qualcuno la cui comprensione dettagliata della tua API è minima, cosa dice la tua API?

Nel caso di sovraccarico, l'utente vede lo stesso nome di funzione, con parametri diversi. A meno che i parametri non diano ragione all'utente di aspettarsi diversamente, l'utente è quindi invitato ad assumere che tutte le funzioni facciano più o meno la stessa cosa.

Nel caso non sovraccarico, l'utente vede 3 diversi nomi di funzioni. Le funzioni hanno nomi simili, quindi l'utente si aspetterebbe un comportamento simile ma diverso.

Quindi l'unica domanda è questa: sono la stessa funzione con parametri diversi, o funzioni che fanno cose simili ma diverse? La registrazione di un'azione revisibile o trasversale è logicamente distinta dalla registrazione di un'azione registrabile?

Solo tu puoi determinare quanto distinti questi concetti sono nel tuo sistema.

    
risposta data 05.05.2017 - 04:23
fonte
3

Sto parlando da un punto di vista dell'ignoranza sul tuo dominio. Prendi quello che ho da dire con un pizzico di sale.

I sovraccarichi con i nomi dei parametri attualmente pubblicati non danno la minima idea su quale tipo di azione sia adatto a un particolare sovraccarico. Quindi, i nomi recordRevisitableAction e recordTraversibleAction hanno più senso per me.

Tuttavia, un'altra opzione è utilizzare il meccanismo di invio tag.

struct GenericAction {};
struct RevisitableAction {};
struct TraversibleAction {};

void recordAction(const QString &moduleName,
                  const QString &actionName,
                  GenericAction tag,
                  QVariantMap parameters = QVariantMap());

void recordAction(const QString &moduleName,
                  const QString &actionName,
                  RevisitableAction tag,
                  QVariantMap parameters = QVariantMap());

void recordAction(const QString &moduleName,
                  const QString &actionName,
                  TraversibleAction tag,
                  QVariantMap parameters = QVariantMap());

Questo ha un paio di vantaggi:

  1. Queste funzioni sono pronte per essere utilizzate da modelli di funzioni e / o modelli di classe se è possibile utilizzare qualsiasi tag struct s come parametri del modello.
  2. Il tipo di azione che può essere utilizzato da un particolare overload è molto chiaro dalle dichiarazioni.

Se hai già classi in conflitto con qualsiasi tag struct s, puoi utilizzare un modello di classe helper.

template <typename T> tag {};
using GenericActionTag = tag<GenericAction>;
using RevisitableActionTag = tag<RevisitableAction>;
using TraversiblebleActionTag = tag<TraversibleAction>;

e quindi usa GenericActionTag , ecc. per sovraccaricare le funzioni.

    
risposta data 05.05.2017 - 07:14
fonte