Неявне блокування (шаблон проєктування)

Матеріал з Вікіпедії — вільної енциклопедії.
Перейти до навігації Перейти до пошуку

Неявне блокування (англ. Implicit Lock) — шаблон проєктування, який пропонує винести блокування на глобальний рівень.

Опис[ред. | ред. код]

Будь-яка схема блокування корисна лише в тому випадку, якщо в ній не зроблено "проколів". Якщо забути накласти блокування, тоді вся схема блокування є марною. Якщо забути звільнити ресурс, він буде заблокований, що приведе до погіршення продуктивності аплікації. Застосування блокування запису, замість блокування читання призведе до використання застарілих даних, а невірне використання версії — до небажаних змін даних іншим користувачем. Окрім цього, механізм паралельного доступу важко тестувати через, що помилки в блокуванні можуть бути не замічені в тестах.

Щоб уникнути помилок розробників під час накладання блокування, даний шаблон пропонує винести блокування на глобальний рівень. Таким чином, можна один раз описати логіку блокування, яка буде застосовуватись до усіх транзакцій у системі (чи лише до необхідних), або ж скористатись вбудованим механізмом, що пропонує фреймворк.

Реалізація[ред. | ред. код]

Реалізуємо неявне блокування за допомогою декораторів. Головна їх перевага, в тому, що об'єкт до яких вони застосовуються навіть не підозрює про зміни у своїй функціональності.

interface IUserRepository
{
    User GetUser(int id);
}

class UserRepository : IUserRepository
{
    public User GetUser(int id)
    {
       return db.Users.Find(id);
    }
}

class ConcurrentUserRepository : IUserRepository
{
    public User GetUser(int id)
    {
       // оскільки в межах сеансу може відбуватись пошук одного і того самого об'єкту декілька разів
       // перевіряємо чи у сеансу вже є блокування на даний ресурс
       LockKey lockKey = LockKey.Build(_appSessionManager.GetSessionId(), id.ToString());
       _lockService.AcquireLock(lockKey);
       try
       {
          return _userRepository.GetUser(id);
       }
       finally
       {
          _lockService.ReleaseLock(lockKey);
       }
    }
}

Тоді при використанні сервісу ми не задумуватимемось про блокування.

var userRepository = new ConcurrentUserRepository(new UserRepository());

// ресурс неявно блокується
var user = userRepository.GetUser(19);

Див. також[ред. | ред. код]

Джерела[ред. | ред. код]