Ele viola qualquer princípio de OOP se uma função de membro não usa nenhuma das propriedades de classe / variáveis de membro?
Não.
OOP não se importa se sua função de membro usa ou não propriedades de classe ou variáveis de membro. OOP se preocupa com o polimorfismo e não com a implementação da codificação. As funções estáticas têm seus usos, mas uma função não deve ser estática simplesmente porque não depende do estado do objeto. Se esse é o seu pensamento, mas não culpe o OOP porque essa ideia não veio do OOP.
O design incorreto [para] não fazer uso de variáveis-membro?
Se você não precisar se lembrar do estado de chamada para chamada, não há uma boa razão para usar o estado.
Qual princípio do design orientado a objetos [viola]?
Nenhum.
Se uma função de membro não usa a variável de membro, essa função de membro sempre deve ser estática?
Não. Esse pensamento tem a seta de implicação indo na direção errada.
Uma função estática não pode acessar o estado da instância
Se a função não precisar acessar o estado da instância, ela poderá ser estática ou não estática
Tornar a função estática aqui depende inteiramente de você. Mas fará com que pareça mais global, se você o fizer. Antes de ficar estático, considere hospedar a função em uma classe sem estado. É mais flexível.
Eu tenho aqui um exemplo OOP de uma função de membro que não usa propriedades de classe ou variáveis de membro.
A função membro (e sua classe sem estado) :
#include <iostream>
class Strategy
{
public:
virtual int execute (int a, int b) = 0; // execute() is a so-called pure virtual
// function. As a consequence, Strategy
// is a so-called abstract class.
};
Três implementações diferentes:
class ConcreteStrategyAdd:public Strategy
{
public:
int execute(int a, int b)
{
std::cout << "Called ConcreteStrategyAdd's execute()\n";
return a + b;
}
};
class ConcreteStrategySubstract:public Strategy
{
public:
int execute(int a, int b)
{
std::cout << "Called ConcreteStrategySubstract's execute()\n";
return a - b;
}
};
class ConcreteStrategyMultiply:public Strategy
{
public:
int execute(int a, int b)
{
std::cout << "Called ConcreteStrategyMultiply's execute()\n";
return a * b;
}
};
Um local para armazenar a escolha da implementação:
class Context
{
private:
Strategy* pStrategy;
public:
Context (Strategy& strategy)
: pStrategy(&strategy)
{
}
void SetStrategy(Strategy& strategy)
{
pStrategy = &strategy;
}
int executeStrategy(int a, int b)
{
return pStrategy->execute(a,b);
}
};
Um exemplo de uso
int main()
{
ConcreteStrategyAdd concreteStrategyAdd;
ConcreteStrategySubstract concreteStrategySubstract;
ConcreteStrategyMultiply concreteStrategyMultiply;
Context context(concreteStrategyAdd);
int resultA = context.executeStrategy(3,4);
context.SetStrategy(concreteStrategySubstract);
int resultB = context.executeStrategy(3,4);
context.SetStrategy(concreteStrategyMultiply);
int resultC = context.executeStrategy(3,4);
std::cout << "\nresultA: " << resultA
<< "\nresultB: " << resultB
<< "\nresultC: " << resultC
<< "\n";
}
Saídas:
Called ConcreteStrategyAdd's execute()
Called ConcreteStrategySubstract's execute()
Called ConcreteStrategyMultiply's execute()
resultA: 7
resultB: -1
resultC: 12
E tudo sem se execute()
preocupar com o estado de qualquer objeto. A Strategy
classe é realmente sem estado. Único estado está em Context
. Objetos sem estado são perfeitamente bons no OOP.
Encontrei este código aqui .