É errado usar algum tipo de parâmetro para determinar o comportamento?

5

De acordo com Está errado usar um parâmetro booleano para determinar o comportamento? , eu não deveria usar um parâmetro booleano para mudar o comportamento dentro de uma função. Como sobre outros tipos de parâmetros?

Por exemplo, se eu tentar usar uma string em vez de booleana:

void f(str){
    if(str==='a'){
        a();
    }else if(str==='b'){
        b();
    }else{
        c();
    }
}

ele também sofre dos mesmos problemas que os parâmetros booleanos? É verdade que devemos dividir métodos com vários comportamentos em vários métodos com apenas um comportamento, independentemente do tipo de parâmetro (por exemplo: booleano, string, enum ...)?

    
por mmmaaa 27.02.2018 / 03:33
fonte

2 respostas

6

Eu gosto de polimorfismo. Eu recomendo para todos os meus amigos. Uma solução polimórfica seria assim:

f(thingy) {
    thingy.doIt()
}

class A { doIt() { a(); } }

class B { doIt() { b(); } }

class C { doIt() { c(); } }

thingyFactory(str){
    if(str==='a'){
        return A();
    }else if(str==='b'){
        return B();
    }else{
        return C();
    }
}

f(thingyFactory("a"))
f(thingyFactory("b"))
f(thingyFactory("c"))

Er espere, parece que você está usando javascript. Aqui está algum polimorfismo funcional.

a = function (){ document.writeln( "<br> a" ); }
b = function (){ document.writeln( "<br> b" ); }
c = function (){ document.writeln( "<br> c" ); }


factory = function(str) {
   if(str==='a'){
        return a;
    }else if(str==='b'){
        return b;
    }else{
        return c;
    }
}

polymorphic = factory('b');
polymorphic();

Como você pode ver, acabamos usando um parâmetro. Não é muito sobre nunca usar parâmetros para tomar decisões. Não se trata de fazer essas decisões com o que foi decidido. Às vezes, tomar essas decisões é caro. Às vezes, podemos criá-las em tempo de compilação. às vezes é difícil de ver, às vezes você quer diferentes áreas de código para lidar com essas duas responsabilidades separadas.

E, claro, às vezes OO puristas mais engenheiro. Nunca faça coisas assim sem entender por que você está fazendo coisas assim. Fazendo isso você recebe alguma coisa. Certifique-se de que você se beneficia disso. Caso contrário, tudo o que você está recebendo é mais código.

    
por 27.02.2018 / 06:16
fonte
0

Eu gosto da resposta do @ CandiedOrange, mas para fins de perfeição, existem outras maneiras de fazer isso também. Você poderia usar um mapa (às vezes chamado de hash ou dicionário) para mapear entradas para funções a serem chamadas. Você não especifica uma linguagem, mas em C ++, seria algo como isto:

#include <iostream>
#include <map>

typedef void (*actionFunction)();

void functionA()
{
    std::cout << "a\n";
}

void functionB()
{
    std::cout << "b\n";
}

int main(int argc, char *argv[])
{
    std::map<char, actionFunction>  functionMap; // <- this is the map of characters to functions
    functionMap [ 'a' ] = functionA;
    functionMap [ 'b' ] = functionB;

    functionMap [ 'a' ](); // <- Calls the function associated with 'a'

    return 0;
}

Você pode fazer uma coisa semelhante em C direto com uma matriz de registros que contêm o mapeamento acima:

#include <stdio.h>

typedef void (*actionFunction)();

typedef struct functionMap {
    char            index;
    actionFunction  func;
} functionMap;

void functionA()
{
    printf("a\n");
}

void functionB()
{
    printf("b\n");
}

int main()
{
    functionMap fMap[] = {  // <- here's the map
        { 'a', functionA },
        { 'b', functionB }
    };
    size_t  numMaps = sizeof(fMap) / sizeof(fMap [ 0 ]);
    char someInput = 'a';

    for (size_t i = 0; i < numMaps; ++i)
    {
        if (fMap [ i ].index == someInput)
        {
            fMap [ i ].func(); // <- this calls the function associated with "someInput"
            break;
        }
    }

    return 0;
}

Elas se encaixam na categoria mais ampla de programação orientada por dados ou por tabela .

    
por 27.02.2018 / 07:01
fonte