Шаблон проектирования для распознавания изменений объекта в C ++? - PullRequest
0 голосов
/ 20 сентября 2018

Я ищу шаблон механики / дизайна, который позволяет настроить объект таким образом, чтобы механик замечал, если объект был изменен после определенной точки существования (например, строительство).В идеале объект мог бы также получить информацию о своем изменении.

Я представляю своего рода интеллектуальный указатель и / или интерфейс, который отмечает доступ для записи и сообщает об этом объекту.

Возможный вариант использования: Объекты, содержимое которых было загружено из файла, должны быть записаны в файл, если они были изменены при разрушении.

Тривиально, вы можете просто реализовать все установщики объекта для индивидуального подсчета доступа к записи.

class A
{
    string filename;
    unsigned int altered;
    int m_a, m_b, M_c;
public:
    A(string filename) : filename(filename), altered(0) { /* parse file */ }
    ~A() { if(altered) {/* write out to file */} } 

    void setA(int a) {altered++; m_a = a}
    void setB(int b) {altered++; m_b = b}
    void setC(int c) {altered++; m_c = c}
};

Это довольно сложно поддерживать и не очень элегантно.Также такое решение не очень переносимо для других типов объектов.

Ответы [ 2 ]

0 голосов
/ 20 сентября 2018

Я не могу вспомнить ни одного паттерна, который каким-то волшебным образом идентифицировал бы, что файл изменился;если вы не находите приемлемым сделать хеш из файла и затем сравнить хэши.В какой-то момент вам придется изменить состояние вашего класса, чтобы он записал измененный файл.Это можно сделать несколькими способами.

Одна вещь, которую вы можете реализовать, - это функция modify, которая изменяет состояние класса и дает пользователю возможность изменить изменяемую версию класса.

void modify(const std::function<void(Mutable_A&)>& modifier) // Implemented in A
{
    modifier(/* the internal stucture */);
    this->writeFile = []{/* write out to file */}; // Then called in destructor
}

Затем он вызывается извне следующим образом:

a.modify([](auto& a){
    a.m_a = 2;
    a.m_b = 3;
    a.setA(2); // If set is prefered
});

Это позволяет избежать добавления произвольного счетчика altered.Вы также можете проверить, действительно ли изменен обратный вызов modifier, и назначить writeFile только если что-то было изменено.Функции set в этом случае будут реализованы только в Mutable_A.Что касается того, как назвать эту модель, я не знаю.

0 голосов
/ 20 сентября 2018

Я не думаю, что есть простое общее решение, так как вам нужно сделать много решений.Например, в вашем коде вы увеличиваете altered, даже если a==m_a.Это может быть правильным в некоторых случаях, но не в других.В любом случае, вот что-то простое, что позволит вам выбрать, что делать в случае изменения члена:

#include <iostream>
using namespace std;

template <typename T> 
struct modification_tracking {
    using clean_up_t = void(*)(const T&);
    modification_tracking(const T& t,clean_up_t clean_up) : 
        t(t), clean_up(clean_up) {}
    ~modification_tracking(){ if(modified) clean_up(t); }
    void set(const T& v){
        modified = t != v;
        t = v;
    }
private:
    T t;
    clean_up_t clean_up;
    bool modified = false;
};

struct foo {
    modification_tracking<int> member{ 1, [](const int& x){ std::cout << x << '\n';}};
};    

int main() {        
    foo f1;
    foo f2;
    f1.member.set(3);
}

Может быть, смарт-указатель с пользовательским удалителем может сделать то же самое и даже больше в лучшем виде.Если объекты легковесны, вы можете даже сохранить оригинал и сравнить его, когда он выходит за рамки видимости.Или вычислить хеш .. вариантов действительно слишком много;)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...