Skip to content

Instantly share code, notes, and snippets.

@jackbergus
Created August 17, 2014 20:02
Show Gist options
  • Save jackbergus/0ae0b0e6c81617d9876f to your computer and use it in GitHub Desktop.
Save jackbergus/0ae0b0e6c81617d9876f to your computer and use it in GitHub Desktop.
A variant of the repository pattern
/*
* Repository-MonoView.cpp
* This file is part of <program name>
*
* Copyright (C) 2014 - Giacomo Bergami
*
* <program name> is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* <program name> is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with <program name>. If not, see <http://www.gnu.org/licenses/>.
*/
#include <vector>
#include <memory>
#include <iostream>
////////////////////////////////////////////////////////////////////////////////
// Pattern: Repository-MonoView
// A variant of the visitor pattern
//
// Repository (client): stores in a local data structure. We want that repository's
// changes could be reported by remote objects that holds a reference to a
// repository's resource.
// Each remote object should have a WeakReference object, in order to notify the
// repository of its destruction.
//
// In order to do this, there is a WeakHolder, which is an Observer of the
// remote's object destruction and Observable by WeakHolder itself when changes
// are submitted.
//
// WeakReference is also an Observer of a local Repository's change
//
// The aim of such pattern is to not store remotely the value of the repository,
// but to change only its coordinates.
////////////////////////////////////////////////////////////////////////////////
// Header
template <typename T> class WeakReference;
template <typename T> class Repository;
template <typename T> class Remote;
/**
* WeakHolder:
* This class contains the object's reference
*/
template <typename T> class WeakHolder {
int index;
Repository<T>* origin;
bool created;
WeakReference<T>* remote; //Object notified
public:
WeakHolder(int pos, Repository<int>* master) :
index{pos}, origin{master}, created{false}
{}
std::unique_ptr<Remote<T>> create(T value);
void decreaseIndex() { --index; }
bool launchUpdateToHolder(int first, int second); //calls holderHasUpdated
void setReference(WeakReference<T>* ptr) { if (!remote) remote = ptr; } //set the remote reference once
void remoteHasBeenDestroyed();
};
/**
* WeakReference:
* This class contains the the remote object's state handler
*/
template <typename T> class WeakReference {
WeakHolder<T>* master;
Remote<T>* up;
public:
WeakReference(WeakHolder<T>* origin, Remote<T>* object) : master{origin}, up{object} {};
~WeakReference() { master->remoteHasBeenDestroyed(); }
bool holderHasUpdated(T first, int second);
};
/**
* Remote:
* Objects created by Repository. WARNING: Non copy-able
*/
template <typename T> class Remote {
std::unique_ptr<WeakReference<T>> remotelylocal{nullptr};
T value;
public:
Remote(T val) : value{val} {};
T getValue() { return value; }
void setValue(T val) { value = val; }
void setReference(std::unique_ptr<WeakReference<T>> ptr) { if (!remotelylocal) remotelylocal=std::move(ptr); }
WeakReference<T>* getReference() { if (!remotelylocal) return nullptr; return remotelylocal.get(); }
};
/**
* Repository:
* Holders' Repository
*/
template <typename T> class Repository {
std::vector<std::unique_ptr<WeakHolder<T>>> holders;
public:
Repository() {};
std::unique_ptr<Remote<T>> createNew(T value);
int size() {return holders.size(); }
void updateObject(int pos, T newvalue) {
holders[pos]->launchUpdateToHolder(newvalue,0);
}
void removeReference(int pos); //Warning: more secure if this is a Repository's lambda
};
//Implementation
template <typename T> bool WeakHolder<T>::launchUpdateToHolder(int first, int second) {
return remote->holderHasUpdated(first,second);
}
template <typename T> std::unique_ptr<Remote<T>> WeakHolder<T>::create(T value) {
std::unique_ptr<Remote<T>> toret{new Remote<T>(value)};
std::unique_ptr<WeakReference<T>> topass{new WeakReference<T>(this,toret.get())};
toret->setReference(std::move(topass));
this->setReference(toret->getReference());
return toret;
}
template <typename T> void WeakHolder<T>::remoteHasBeenDestroyed() {
origin->removeReference(index);
}
template <typename T> bool WeakReference<T>::holderHasUpdated(T first, int second) {
up->setValue(first);
return true;
}
template <typename T> std::unique_ptr<Remote<T>> Repository<T>::createNew(T value) {
holders.emplace(holders.end(),new WeakHolder<T>(holders.size(),this));
return holders[holders.size()-1]->create(value);
}
template <typename T> void Repository<T>::removeReference(int pos) {
holders.erase(holders.begin()+pos);
for (int i=pos; i<holders.size(); i++)
holders[i]->decreaseIndex();
}
/** EXAMPLE */
int main(void) {
Repository<int> bordello;
std::unique_ptr<Remote<int>> snd = repo.createNew(2);
std::unique_ptr<Remote<int>> hrd = repo.createNew(3);
{
std::unique_ptr<Remote<int>> fst = repo.createNew(1);
bordello.updateObject(2,55);
std::cout << fst->getValue() << std::endl;
//fst is now destroyed
}
std::cout << "Size: " << repo.size() << std::endl; //fst holder is hence removed
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment