Eine reine Funktion ist eine, die:
- Gibt immer das gleiche Ergebnis mit den gleichen Argumenten
- Hat keine beobachtbaren Nebenwirkungen (zB Zustandsänderungen)
Angenommen, wir schreiben Code für die Benutzeranmeldung, in dem wir überprüfen möchten, ob der angegebene Benutzername und das angegebene Kennwort korrekt sind, und verhindern, dass sich der Benutzer anmeldet, wenn zu viele Fehlversuche auftreten. In einem imperativen Stil könnte unser Code folgendermaßen aussehen:
bool UserLogin(string username, string password)
{
var user = _database.FindUser(username);
if (user == null)
{
return false;
}
if (user.FailedAttempts > 3)
{
return false;
}
// Password hashing omitted for brevity
if (user.Password != password)
{
_database.RecordFailedLoginAttempt(username);
}
return true;
}
Es ist ziemlich klar, dass dies keine reine Funktion ist:
- Diese Funktion wird nicht immer das gleiche Ergebnis für ein gegebene
username
und password
Kombination als das Ergebnis hängt auch von dem Benutzerdatensatz in der Datenbank gespeichert.
- Die Funktion kann den Status der Datenbank ändern, dh sie hat Nebenwirkungen.
Beachten Sie auch, dass wir zum Testen dieser Funktion zwei Datenbankaufrufe verspotten müssen, FindUser
und RecordFailedLoginAttempt
.
Wenn wir diesen Code in einen funktionaleren Stil umgestalten würden, könnten wir am Ende etwas Ähnliches erhalten:
bool UserLogin(string username, string password)
{
var user = _database.FindUser(username);
var result = UserLoginPure(user, password);
if (result == Result.FailedAttempt)
{
_database.RecordFailedLoginAttempt(username);
}
return result == Result.Success;
}
Result UserLoginPure(User user, string pasword)
{
if (user == null)
{
return Result.UserNotFound;
}
if (user.FailedAttempts > 3)
{
return Result.LoginAttemptsExceeded;
}
if (user.Password != password)
{
return Result.FailedAttempt;
}
return Result.Success;
}
Beachten Sie, dass die UserLogin
Funktion zwar immer noch nicht rein ist, die UserLoginPure
Funktion jetzt jedoch eine reine Funktion ist. Infolgedessen kann die Kernlogik der Benutzerauthentifizierung auf Einheit getestet werden, ohne dass externe Abhängigkeiten verspottet werden müssen. Dies liegt daran, dass die Interaktion mit der Datenbank weiter oben im Aufrufstapel erfolgt.