Различные способы реализации функции "грязного" флага
Почти каждый программист сделал это один раз в своей жизни: установил некоторый флаг, если изменилось значение переменной. Там всегда много свойств, и вы хотите отслеживать, если что-то изменилось
- в любом свойстве
- в определенном свойстве
- или в некоторых наборах свойств
Я заинтересован в различных способах реализации функциональности "грязного флага" для вышеупомянутых ситуаций, кроме того, что флажок стандартного объекта с грязным флагом обновляется при каждом изменении свойства. Там должно быть что-то лучше, чем положить "грязный = истинный" в каждый сеттер: он просто выглядит уродливым и утомительным.
Ответы
Ответ 1
Для моего DAO я сохраняю копию исходных значений, полученных из базы данных. Когда я отправляю его для обновления, я просто сравниваю исходные значения с текущим. Это стоит немного в обработке, но это намного лучше, чем наличие грязного флага на каждое свойство.
EDIT, чтобы еще больше оправдать отсутствие грязного флага: если свойство возвращается к его первоначальному значению, нет способа отразить это, грязный флаг продолжает быть грязным, потому что исходное значение было потеряно.
Ответ 2
У меня был базовый класс Entity, предоставляющий Dirty/Removed Logic.
При написании Entity-подклассов вы можете сделать что-то вроде:
public string Name
{
get { return name; }
set { setValue("Name", value); }
}
Это прекрасно работает, но имеет болезнь "уродливой струны"...
Сегодня вы можете использовать выражения Lambda Expressions для исключения строк:
set {setValue(x => x.Name, value);}
Или, и я думаю, что это лучшее решение, вы можете использовать AOP:
https://www.postsharp.net/
Таким образом, вы можете определять действия по атрибутам. Вы создаете атрибут и указываете, что, когда пользователь изменяет связанное свойство, объект становится грязным.
Кроме того, вы можете сохранить список свойств в своем классе (базовый Entity), который будет помнить измененные свойства и получить доступ к этому списку из вашего кода AOP.
Ответ 3
Я создал класс под названием DirtyValue<T>
, который имеет исходное значение и текущее значение. При первом использовании он устанавливает как исходное значение, так и текущее значение. Последовательные вызовы устанавливают только текущее значение.
Вы можете узнать, изменилось ли это, сравнив два, с свойством readonly bool, называемым IsDirty(). Используя этот метод, вы также можете получить доступ к исходному значению.
Ответ 4
Если вы устанавливаете "грязный" флаг, понимаете, что вы сохраняете состояние. В какой-то момент вам нужно принять действие на основе этого состояния, иначе вам не нужно будет держать флаг. Итак, тогда возникает вопрос: есть ли другой способ инициировать необходимое действие? Отправка сообщений какого-то рода? Кто потребляет "грязное" состояние и принимает меры, и есть ли более чистый интерфейс для этого уведомления?
Ответ 5
В некоторых ситуациях с задачей записи данных и задачей независимого чтения я дал каждой задаче переменную updateCount
. Производитель увеличивает свой счет каждый раз, когда он пишет. Всякий раз, когда читатель просыпается и считает, что его счет меньше количества производителей, он обновляет текущие значения. Вам нужна небольшая специальная обработка для переполнения счетчика, но это довольно просто реализовать.
Я успешно использовал этот метод в симуляциях - где производитель - это физический цикл, а читатель - это 3D-дисплей.
Ответ 6
Я бы поместил change() в каждый сеттер, т.е. вызовет частный метод вместо простого изменения флага. Затем этот метод может устанавливать флаг или выполнять любую обработку, например. он также может уведомлять обо всех наблюдателях.
Ответ 7
Интересная альтернатива явному подходу dirty=true
, хотя она, вероятно, слишком сложна для большинства ситуаций и часто неприменима, будет использовать защитные страницы. Задайте страницу памяти как доступную только для чтения (например, VirtualProtect() в Windows) и поймайте сигнал/исключение, когда программа пытается записать страница. Сделайте запись о том, что страница была изменена, затем измените флаги защиты страницы на запись и возобновите выполнение.
Это метод, обычно используемый операционными системами для определения необходимости записи страницы в файл подкачки, прежде чем она будет выведена из ОЗУ.
Ответ 8
Возможно, вы захотите взглянуть на переопределение gethashcode и равные методы ваших объектов домена и сохранить исходные хэш-коды в хэш-таблице с помощью ключа объекта. Затем создайте процесс, который берет объект, находит его ключ в хеш-таблице и сравнивает хеш-значения.
- Если хеш же, никаких изменений. (не отправлять в репозиторий или базу данных)
- если hash different, объект имеет изменения. (обновление)
- Если ключ не найден, объект новый. (Вставка)
- Не знаете, как определить, нужно ли удалять объект, кроме удаления процесса по запросу, и не использовать для них отслеживание hashcode.
Я не пробовал это, и хеш-таблица, возможно, не лучший способ отслеживать ключи объектов/хэш-значения. Он сохранил бы mem, только отслеживая только хэш-коды и ключи. Я не уверен на 100%, но я думаю, что некоторые ормы могут использовать этот метод в своих объектах контекста данных/отслеживания.