Натягуємо ФП на ООП

Деякий час тому, повернувшись після піврічного відпустки у функціональному світі, тому в ООП, я в який раз наступив на звичні граблі: випадково змінив стан.
private double fBm(Vector2D v, int y)
{
double result = 0f;
double freq = Frequency;

for (int i = 0; i < Octaves; ++i)
{
result += NoiseFn(перестановок, v * freq) * Amplitude;
freq *= Lacunarity;
Amplitude *= Gain; // <-- Ось тут.
}

return result;
}

ФП потрібно особливо постаратися щоб отримати такий баг, а в деякий мовах неможливо в принципі. Салат з корисною роботи і стану класу не радував, простір для помилок навіть у цій четвірці рядків занадто широкий. Я став думати як можна зменшити площа цих грабель і вивів наступне:
По-перше потрібно зробити
this
обов'язковим. Поставити поле не з тієї сторони вираження занадто легко. Якщо б я скрізь явно вказав контекст, швидше за все одразу помітив, що ступив. На жаль, компілятор C# не можна змусити вимагати
this
, а в статичних перевірок студії є лише правило яке працює навпаки, тобто змушує прибирати
this
. Так що, мабуть, доведеться писати своє.
По-друге потрібно виключити використання полів класу з тіла методу, а всі зміни записувати в кінці методу, якщо вони є. У нас виходить три абзаци. В першому ми оголошуємо все що нам знадобиться, у другому робимо корисну роботу, у третьому зберігаємо стан.
public void DoAThing(int input)
{
// Перший абзац
int a = this.A;
int b = this.B;
int result = 0;

// Другий абзац
for (int i = 0; i < input; ++i)
result += (a + b) * i;

// Абзац третій
this.Thing = result;
}

В першому абзаці все стан, який потрібно ми зберігаємо локально.
У другому,
this
не фігурує.
У третьому
this
завжди повинен бути першим словом. Тут же будуть викликатися інші методи, які змінюють стан.
return
можна додати в будь-яке місце, на поведінку методу він не вплине.
Плюси
  • Багів з випадковим зміною стану стане менше.
  • Відсутність третього абзацу робить метод чистої функцією, а значить його можна запускати паралельно.
Мінуси
  • Дисципліна. Фу-фу-фу. Без автоматичних перевірок, легко все зіпсувати.
  • У деяких випадках цей підхід буде працювати повільніше.
  • Може виглядати дивно або нерозумно. Ось наприклад:
    {
    int a = this.A;
    int b = this.B;
    return a + b;
    }
Замість висновку
Як думаєте? В цьому є сенс або я парюся?
Якщо ви вже робите подібне або натягаєте інші частини ФП на ООП, будь ласка поділіться.
Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.