Does it violate any OOP principal if a member function does not use any of class properties/member variables?
No.
A OOP non interessa se la funzione membro usa, o non usa, proprietà di classe o variabili membro. OOP si preoccupa del polimorfismo e non dell'implementazione di hard coding. Le funzioni statiche hanno i loro usi ma una funzione non dovrebbe essere statica semplicemente perché non dipende dallo stato dell'oggetto. Se questo è il tuo modo di pensare bene, ma non dare la colpa a OOP perché quell'idea non è venuta da OOP.
Is [it] bad design [to not] make use of member variables?
Se non hai bisogno di ricordare lo stato da una chiamata all'altra, non c'è una buona ragione per usare lo stato.
Which principle of Object oriented design [does] it violate?
Nessuno.
If a member function does not use the member variable then that member function should always be made static?
No. Questo pensiero ha la freccia implicita che va nella direzione sbagliata.
-
Una funzione statica non può accedere allo stato dell'istanza
-
Se la funzione non ha bisogno di accedere allo stato dell'istanza, la funzione può essere statica o non statica
Rendere la funzione statica qui dipende completamente da te. Ma lo renderà più come un globale se lo fai. Prima di andare statico, considera l'hosting della funzione in una classe senza stato. È più flessibile.
Ho qui un esempio OOP di una funzione membro che non usa le proprietà di classe o le variabili membro.
La funzione membro (ed è una classe stateless) :
#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.
};
Tre diverse implementazioni:
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;
}
};
Un luogo in cui memorizzare la scelta dell'implementazione:
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);
}
};
Un esempio di utilizzo
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";
}
Uscite:
Called ConcreteStrategyAdd's execute()
Called ConcreteStrategySubstract's execute()
Called ConcreteStrategyMultiply's execute()
resultA: 7
resultB: -1
resultC: 12
E tutto senza execute()
attento allo stato di qualsiasi oggetto. La classe Strategy
è in realtà senza stato. Lo stato solo è in Context
. Gli oggetti apolidi stanno perfettamente bene in OOP.
Trovato questo codice qui .