Чистая функция является тот , который:
- Буду всегда дают тот же результат , учитывая те же аргументы
- Не имеет видимых побочных эффектов (например, изменения состояния)
Предположим, мы пишем некоторый код для обработки входа пользователя, где мы хотим проверить правильность введенных имени пользователя и пароля и предотвратить вход пользователя в систему, если слишком много неудачных попыток. В императивном стиле наш код может выглядеть так:
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;
}
Довольно ясно, что это не чистая функция:
- Эта функция не всегда дает тот же результат для заданного
usernameи passwordкомбинации , как результат также зависит от записи пользователя , хранящейся в базе данных.
- Функция может изменять состояние базы данных, то есть имеет побочные эффекты.
Также обратите внимание, что для модульного тестирования этой функции нам нужно смоделировать два вызова базы данных, FindUserи RecordFailedLoginAttempt.
Если бы мы реорганизовали этот код в более функциональный стиль, мы могли бы получить что-то вроде этого:
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;
}
Обратите внимание, что хотя UserLoginфункция все еще не является чистой, UserLoginPureфункция теперь является чистой функцией, и в результате логика аутентификации пользователя может быть проверена модульно, без необходимости имитировать какие-либо внешние зависимости. Это связано с тем, что взаимодействие с базой данных обрабатывается выше стека вызовов.