È una cattiva pratica definire / utilizzare le funzioni "Preset"

6

Diciamo che ho una funzione estremamente robusta e versatile:
void DoAnything(action, target, context)

Nel mio programma, il 90% delle volte chiamo questa funzione, è con gli stessi parametri:
DoAnything(eat, food, lunchtime);

È una cattiva forma per me definire una funzione come:
void EatLunch(){ DoAnything(eat, food, lunchtime); }

E chiamalo invece?

    
posta Jordaan Mylonas 07.10.2011 - 07:11
fonte

3 risposte

8

È una cosa buona da fare quando si scopre che il codice è più leggibile e più manutenibile quando è avvolto usando gli argomenti invarianti. Lo faccio spesso.

    
risposta data 07.10.2011 - 07:33
fonte
6

Quando scrivi una libreria, l'aggiunta di wrapper di convenienza è spesso un servizio per i tuoi utenti.

Ad esempio, supponiamo di aver scritto una libreria di compressione del flusso in C. Il mio punto di ingresso altamente versatile potrebbe essere:

Stream *compress_stream(Stream *input, StreamOptions *opts);

Tuttavia, molti utenti vorranno semplicemente una funzione come questa:

void *compress(const void *data, size_t length, size_t *out_length);

compress_stream è più versatile: può sia consumare input sia produrre output pigramente e l'utente può fornire parametri aggiuntivi (ad esempio algoritmo, qualità, ecc.)

Tuttavia, se un utente ha semplicemente un blob di dati che desidera rendere più piccoli, la mia funzione compress_stream sarà estremamente ingombrante di per sé. L'utente dovrà conoscere il mio oggetto Stream :

typedef struct Stream Stream;

struct Stream
{
    size_t (*read)(Stream *s, void *buffer, size_t len);
    void free(Stream *s);
};

Quindi dovranno implementare compress nei loro termini:

typedef struct
{
    Stream stream;
    const char *data;
    size_t remaining;
} SimpleStream;

size_t SimpleStream_read(Stream *s, void *buffer, size_t len)
{
    SimpleStream *ss = container_of(s, Stream, stream);

    if (len > ss->remaining)
        len = ss->remaining;

    memcpy(buffer, ss->data, len);
    ss->data += len;
    ss->remaining -= len;
    return len;
}

void SimpleStream_free(Stream *s)
{
    free(container_of(s, Stream, stream));
}

Stream *SimpleStream_new(const void *data, size_t length)
{
    SimpleStream *ss = stream_new(sizeof(SimpleStream),
                                  SimpleStream_read,
                                  SimpleStream_free);
    if (ss == NULL)
        return NULL;

    ss->data = data;
    ss->remaining = length;
    return &ss->stream;
}

void *consume(Stream *s, size_t *out_length)
{
    char *buffer;
    size_t buffer_length = 0;
    size_t buffer_alloc = 16;

    buffer = malloc(buffer_alloc + 1);
    if (buffer == NULL)
        return NULL;

    for (;;) {
        size_t readlen;

        readlen = s->read(s, buffer + buffer_length, buffer_alloc - buffer_length);
        if (readlen == 0)
            break;

        buffer_length += readlen;
        assert(buffer_length <= buffer_alloc);
        if (buffer_alloc - buffer_length < 16) {
            char *tmp;

            buffer_alloc *= 2;
            tmp = realloc(buffer, buffer_alloc + 1);
            if (tmp == NULL) {
                free(buffer);
                return NULL;
            }
            buffer = tmp;
        }
    }

    buffer[buffer_length] = 0;
    *out_length = buffer_length;
    return buffer;
}

void *compress(const void *data, size_t length, size_t *out_length)
{
    Stream *input;
    Stream *output;
    void *ret;

    input = SimpleStream_new(data, length);
    output = compress_stream(input, NULL);
    input->free(input);
    ret = consume(output, out_length);
    output->free(output);
    return ret;
}

Questo può essere un esempio forzato, ma ho visto le librerie trascurare di includere wrapper semplici in più occasioni. Per gli utenti che implementano questi wrapper nel loro codice, dovranno imparare di più sulla tua libreria di quanto non volessero realmente.

    
risposta data 07.10.2011 - 09:00
fonte
5

No, è una buona forma per farlo. Definendo cosa significa EatLunch() in un posto si riduce la ripetizione del codice. Inoltre, se mai hai bisogno di cambiare cosa significa EatLunch() , devi farlo in un unico posto.

    
risposta data 07.10.2011 - 09:01
fonte

Leggi altre domande sui tag