→ Пошук по сайту       Увійти / Зареєструватися
Знання Патерни Патерни поведінки — Behavioral patterns

18. Хранитель — Memento

18.	Хранитель — Memento

Якщо ви коли небуть бавилися в «стрілялки», то дуже вірогідно, що ви знайомі із значенням хот-кіїв F5 та F9. I, навіть, якщо ви таки не мали шансу в житті погратися в «шпільки», ідея швидкого збереження поточного стану і відновлення до нього ідеологічно є знайомою (навіть якщо це було Ctrl+Z у програмі Word). Натискаючи F5 ви зберігаєте поточне місце знаходження і рівні життя/броні та, можливо, ще якусь інформацію, наприклад, скільки монстрів було вже вбито на даній позиції (напевно для того, щоб не «мочити» їх заново). Коли клавіша F9 натискається відбувається повернення до попереднього збереженого стану.

Під час збереження стану, швидше за все, вам не дуже хочеться, щоб ця інформація була доступна іншими класами (інкапсуляція стану), таким чином ви будете певні, що ніхто не зменшить рівень життя. Також може знадобитися функціональність по збереженню послідовності станів. Наприклад, можливість повернутися на 2 або 3 збереження назад натискаючи Shift+F9 (+F9). Як це можна реалізувати?

Хранитель використовується тоді, коли ви хочете відмінити операції без відображення внутрішньої структури Хазяїна (Originator — гра у нашому прикладі). Координація операцій здійснюється Опікуном (Caretaker — контроллер гри), який надає можливість простого збереження миттєвих станів системи без уявлення що ці стани собою являють.

Давайте глянемо на реалізацію:

Уривок коду 18.1. Гра

 public class GameOriginator
{
    // Стан містить здоров’я та к-ть вбитих монстрів
    private GameState _state = new GameState(100, 0);

    public void Play()
    {
      // Імітуємо процес гри – 
      // здоров’я повільно погіршується, а монстрів стає все менше
      Console.WriteLine(_state.ToString());
      _state = new GameState((int)(_state.Health*0.9), _state.KilledMonsters + 2);
    }
 

    public GameMemento GameSave()
    {
        return new GameMemento(_state);
    }
 
    public void LoadGame(GameMemento memento)
    {
        _state = memento.GetState();
    }
}

Уривок коду 18.2. Хранитель GameMemento

 public class GameMemento
{
    private readonly GameState _state;
 
    public GameMemento(GameState state)
    {
        _state = state;
    }
 
    public GameState GetState()
    {
        return _state;
    }
}

Таким чином, цей клас може згенерувати екземпляр Хранителя із поточним знімком (станом) гри, в той же час можна витягнути стан із уже існуючого Хранителя, але при цьому ніхто більше не буде працювати із станом гри напряму.
Нижче наведений код може тільки завантажити останній збережений «сейв», але все можна легко вдосконалити.

Уривок коду 18.3. Відповідальний

 public class Caretaker
{
    private readonly GameOriginator _game = new GameOriginator();
    private readonly Stack< GameMemento > _quickSaves = new Stack< GameMemento >();
 
    public void ShootThatDumbAss()
    {
        _game.Play();
    }
 
    public void F5()
    {
        _quickSaves.Push(_game.GameSave());
    }
 
    public void F9()
    {
        _game.LoadGame(_quickSaves.Peek());
    }
} 

Припустимо що гра протікала так, як у наступному уривку коду:

Уривок коду 18.4. Використання

 var caretaker = new Caretaker();
caretaker.F5();
caretaker.ShootThatDumbAss();
caretaker.F5();
caretaker.ShootThatDumbAss();
caretaker.ShootThatDumbAss();
caretaker.ShootThatDumbAss();
caretaker.ShootThatDumbAss();
caretaker.F9();
caretaker.ShootThatDumbAss();

В такому випадку наша демонстраційна програма згенерує такий вивід (State має перевантажений метод ToString):

 Health: 100 
Killed Monsters: 0
Health: 90 
Killed Monsters: 2
Health: 81 
Killed Monsters: 4
Health: 72 
Killed Monsters: 6
Health: 64 
Killed Monsters: 8
Health: 90 
Killed Monsters: 2

А ось проста UML діаграма, намальована для цього прикладу:

UML-діаграма 10. Хранитель стану гри

По матеріалам книги Андрія Будая "Дизайн патерни – просто, як двері". Матеріал розміщується за домовленістю з автором.
Робота представлена за умовами ліцензії Creative Commons Attribution-NonCommercial 3.0 Unported License.

загрузка...
Сторінки, близькі за змістом