Hlavní navigace

Programovací paradigmata

24. 4. 2018 3:11 (aktualizováno) Petr Suchý

Víte, co to jsou programovací paradigmata? Budu mít tří programátory s různou úrovní znalostí. Zadám jim stejný úkol. Tento úkol bude spočívat ve vytvoření programu pro sečtení celočíselné řady, která se nachází v textovém souboru. Programátoři jsou různě zkušení, a proto každý zvolí odlišný přístup.

Naivní paradigma

První programátor je začátečník. Vytvoří jednoduchý program.

// sum1.c

#include <stdio.h>

int main(int argc, char* argv[])
{
    int res = 0;
    int n;

    /*
        Cyklus se přeruší, pokud scanf() obdrží ze std. vstupu řetězec,
        který nelze konvertovat na celé číslo, nebo dojde-li k uzavření
        vstupního proudu.
    */

    while (scanf("%d", &n) == 1) {
        res += n;
    }

    printf("\nResult: %d\n", res);

    return 0;
}

A sečte číselnou řadu:

$ ./sum1 < numbers.txt

Procedurální paradigma

Druhý programátor je zkušenější. Zadaný úkol rozdělí na dvě části – načtení souboru a součet číselně řády. Pro každou část vytvoří funkci.

// sum2.c

#include <stdio.h>
#include <stdlib.h>

/*
    Funkce načte pole celých čísel ze souboru file_name.
    V případě úspěchu nastaví do nums ukazatel na začátek pole a
    vrátí počet načtených prvků. V případě neúspěchu vrátí hodnotu -1.
*/

int load_file_nums(int** nums, const char* file_name)
{
    int nums_count = 0;
    int* ret_ptr;
    int* tmp;
    FILE* fp;
    int n;

    if (!nums) {
        return -1;
    }

    // Otevřeme zdrojový soubor.

    fp = fopen(file_name, "r");

    if (!fp) {
        return -1;
    }

    // Postupně čteme čísla ze souboru

    while (fscanf(fp, "%d", &n) == 1) {

        // Pokud je počet přečtených čísel > 0

        if (nums_count) {

            // Zvětšíme velikost paměti pro další číslo.

            tmp = realloc(ret_ptr, (nums_count + 1) * sizeof(int));

            if (tmp) {

                ret_ptr = tmp;

            }
            else {

                free(ret_ptr);
                fclose(fp);

                return -1;
            }

        }
        else {

            // Alokujeme paměť pro první číslo.

            ret_ptr = malloc(sizeof(int));

            if (!ret_ptr) {

                fclose(fp);

                return -1;
            }

        }

        // Uložíme číslo do pole.

        ret_ptr[nums_count++] = n;

    }

    // Uzavřeme soubor.

    fclose(fp);

    // Vrátíme ukazatel na pole a počet prvků v poli.

    *nums = ret_ptr;

    return nums_count;
}

/*
    Funkce sečte celá čísla v poli nums o délce len a vrátí výsledek.
*/

int sum(int* nums, int len)
{
    int res = 0;
    int i;

    if (nums) {

        for (i = 0; i < len; i++) {
            res += nums[i];
        }

    }

    return res;
}

int main(int argc, char* argv[])
{
    int* nums;
    int nums_count;
    int i;

    if (argc != 2) {

        fprintf(stderr, "Usage %s <file-name>\n", argv[0]);

        return 1;
    }

    // Načteme pole čísel ze souboru.

    nums_count = load_file_nums(&nums, argv[1]);

    if (nums_count == -1) {

        fprintf(stderr, "Error loading file!");

        return 1;
    }

    // Sečteme čísla v poli a zobrazíme výsledek.

    printf("\nResult: %d\n", sum(nums, nums_count));

    // Uvolníme paměť pro pole.

    free(nums);

    return 0;
}

A sečte číselnou řadu:

$ ./sum2 numbers.txt

Objektově orientované paradigma

Třetí programátor je profesionál. Využije principy OOP.

// sum3.cpp

#include <iostream>
#include <fstream>

using namespace std;

class csum {

    private:

        int m_tsum; // mezisoučet

    public:

        // Konstruktor

        csum(): m_tsum(0)
        {
        }

        // Přičte číslo n k mezisoučtu.

        void add(int n)
        {
            m_tsum += n;
        }

        // Vrátí výsledek součtu.

        int result()
        {
            return m_tsum;
        }

        // Inicializuje nové sčítání.

        void reset()
        {
            m_tsum = 0;
        }

        // Sečte čísla ze vstupního proudu.

        istream& from_stream(istream& is)
        {
            int n;

            reset();

            while (is >> n) {
                add(n);
            }

            return is;
        }

};

// Přetížení operátoru >> pro vstupní proud.

istream& operator>>(istream& is, csum& sum)
{
    return sum.from_stream(is);
}

int main(int argc, char* argv[])
{
    fstream fs;
    csum sum;

    if (argc != 2) {

        cerr << "Usage: " << argv[0] << " <file-name>" << endl;

        return 1;
    }

    // Otevřeme soubor.

    fs.open(argv[1]);

    if (!fs.is_open()) {

        cerr << "Error opening file!" << endl;

        return 1;
    }

    // Sečteme čísla v souboru.

    fs >> sum;

    // Zobrazíme výsledek.

    cout << "Result: " << sum.result() << endl;

    return 0;
}

A sečte číselnou řadu:

$ ./sum3 numbers.txt

Závěr

Na konec všechny požádám, aby pomocí svého programu sečetli číselnou řadu ze souboru, který se nachází na webu. Procedurální programátor udělá další funkci. Objektově orientovaný programátor vytvoří novou třídu. A co udělá naivní programátor? Chvíli bude přemýšlet, a potom napíše:

$ wget -qO- http://.../numbers.txt | ./sum

Pozn. Uvedené příklady jsou funkční. Hlavičkové soubory nejsou použity záměrně, aby byl ukázkový kód kratší.