Чи повинні слухачі подій містити слабкі посилання?


9

Зазвичай слухачі подій не повинні переживати об'єкт, який їх зареєстрував.

Чи означає це, що слухачі подій за замовчуванням повинні містити слабкі посилання (зберігаються у слабких колекціях, за допомогою яких слухачі об'єктів зареєстровані)?

Чи є дійсні випадки, коли слухач повинен переживати свого творця?

А може така ситуація є помилкою, і її не можна допускати?


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

Відповіді:


7

Чому слухачі подій не повинні переживати об'єкт, який їх зареєстрував? Схоже, ви припускаєте, що слухачів подій слід зареєструвати за допомогою методів управління (якщо ми візьмемо приклад GUI) - а точніше - методами об'єктів класів, які успадковують елементи керування інструментарію GUI. Це не є необхідністю, наприклад, ви можете використовувати спеціалізований об'єкт для реєстрації слухачів подій і викопувати цей об'єкт згодом.

Крім того, якби слухачі подій були слабкими, вам доведеться фактично зберігати посилання на них, навіть якщо ви ніколи не використовуєте це посилання. Якщо цього не зробити, слухач буде зібраний у випадковий час. Отже, ми отримуємо помилку, яка є

  • Легко створити помилково (все, що вам потрібно зробити, це забути збереження об'єкта в довідковій змінній, яку ви ніколи не будете використовувати).
  • Важко помітити (помилку ви отримаєте лише тоді, коли GC збирає цей об’єкт).
  • Важко налагоджувати (у сеансі налагодження - який завжди працює як сеанс випуску - ви будете стикатися з цим помилкою лише в тому випадку, якщо GC зібрав об'єкт).

І якщо уникнути помилок, це недостатньо хороший стимул, ось ще кілька:

  1. Вам доведеться придумати ім’я кожного створеного вами слухача.

  2. Деякі мови використовують статичний аналіз, який генерує попередження, якщо у вас є поле приватного члена, яке ніколи не записується або ніколи не читається. Вам доведеться використовувати механізм, що дозволяє це перекрити.

  3. Слухач події щось робить, і як тільки об’єкт, на який він має сильну відсилку, буде зібраний, він перестане щось робити. Тепер у вас є щось, що впливає на стан програми і залежить від GC - це означає, що GC впливає на конкретний стан програми. І це БАД !

  4. Поводження із слабкими посиланнями відбувається повільніше, оскільки у вас інший рівень непрямості та оскільки вам потрібно перевірити, чи було посилання зібрано. Це не було б проблемою, якщо потрібне наявність слухачів подій у слабких посиланнях - але це не так!


5

Загалом, так, слід використовувати слабкі посилання. Але спочатку нам повинно бути зрозуміло, що ви маєте на увазі під «слухачами подій».

Відкликання дзвінків

У деяких стилях програмування, особливо в умовах асинхронних операцій, прийнято представляти частину обчислення як зворотний виклик, який виконується в певну подію. Наприклад, Promise[ 1 ] може мати thenметод, який реєструє зворотний виклик після завершення попереднього кроку:

promise =
    Promise.new(async_task)                # - kick off a task
    .then(value => operation_on(value))    # - queue other operations
    .then(value => other_operation(value)) #   that get executed on completion
... # do other stuff in the meanwhile
# later:
result = promise.value # block for the result

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

Шаблон спостерігача

У шаблоні спостерігачів суб'єкт має список залежних спостерігачів. Коли суб'єкт переходить у певний стан, спостерігачів повідомляють відповідно до деякого інтерфейсу. Спостерігачі можуть бути додані до теми та видалені з них. Ці спостерігачі не існують у семантичному вакуумі, але чекають подій з якоюсь метою.

Якщо цієї мети більше не існує, спостерігачів слід видалити з теми. Навіть у мовах, зібраних зі сміттям, це вилучення, можливо, доведеться виконувати вручну. Якщо ми не зможемо видалити спостерігача, він буде зберігатися в живих за допомогою посилання від суб'єкта до спостерігача, а разом з цим і всіх об'єктів, на які спостерігач посилається. Це втрачає пам'ять і погіршує продуктивність, оскільки (зараз марний) спостерігач все ще буде повідомлений.

Слабкі посилання виправляють цю витік пам'яті, оскільки вони дозволяють спостерігачеві збирати сміття. Коли суб'єкт проходить навколо, щоб повідомити всіх спостерігачів і виявить, що одне зі слабких посилань на спостерігача порожнє, це посилання може бути безпечно видалено. Крім того, слабкі посилання можуть бути реалізовані таким чином, що дозволяє суб'єкту зареєструвати зворотний виклик очищення, який видалить спостерігача після збору.

Але зауважте, що слабкі посилання - це лише допомога, яка обмежує шкоду, забуваючи зняти спостерігача. Правильним рішенням було б зробити так, щоб спостерігач був відсторонений, коли це вже не потрібно. Варіанти включають:

  • Робити це вручну, але це схильне до помилок.

  • Використовуючи щось подібне для пробного використання ресурсу на Java або usingв C #.

  • Детерміновані руйнування, наприклад, через ідіому RAII. Зауважте, що в мові з детермінованим вивезенням сміття це все ще може вимагати слабких посилань суб'єкта на спостерігача, щоб викликати руйнівник.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.