Есть довольно мало информации по этой теме. Это больше вопрос дизайна, но я приведу примеры.
Допустим, я буквально хочу обойти профиль класса, который диктует политику пользователя.
struct ApplicationAllowedPolicy
{
public:
bool hasAccess() { return true; }
}
struct ApplicationProhibitedPolicy
{
public:
bool hasAccess() { return false; }
}
template<typename ApplicationPolicy>
class Profile : private ApplicationPolicy
{
bool hasAccess() { return ApplicationPolicy::access(); }
}
int main()
{
Profile<ApplicationAllowedPolicy> allowed;
Profile<ApplicationProhibitedPolicy> prohibited;
// do something with allowed & prohibited
}
Все вышеперечисленное прекрасно и замечательно, но давайте предположим, что есть много политик, которые необходимо прочитать. 5 Похоже на реальное число в реальном мире, хотя может быть и больше. Затем предположим, что этот профиль будет применяться к сотням экземпляров, причем 5 политик сильно различаются. Для загрузки поведение политики будет известно только во время выполнения (чтение из файла, базы данных и т. Д.). Это быстро становится невероятным, если я что-то полностью не пропустил.
Я думал о создании нетипового шаблона в качестве политики.
template<int N>
struct ApplicationPolicy
{
int policy = N;
};
Profile<ApplicationPolicy<1>> allowed;
Profile<ApplicationPolicy<0>> prohibited;
Я думаю, что это действительно сработает для моей ситуации, но мне интересно, не упускает ли это смысл дизайна, основанного на политике. У меня возникают проблемы, когда я вижу плюсы в этом, просто чтобы Profile был нормальной структурой и просто устанавливал для своих членов данных значение true / false по мере необходимости.
Мысли?
Разработка на основе политик очень полезна, когда поведение класса существенно меняется в зависимости от политики. Например, скажем, вы хотите, чтобы ваш класс использовался как в многопоточном, так и в обычном контексте. Тогда вы могли бы реализовать это как политику потоков:
class SingleThreadedPolicy { /* ... */ }; // lock() does nothing
class MultiThreadedPolicy { /* ... */ }; // lock() actually locks
template<class T, class ThreadingPolicy>
class Queue {
ThreadingPolicy threadPol_;
// ...
T pop() {
threadPol_.lock();
// remove an element from the queue
threadPol_.unlock();
return element;
}
};
Теперь, два других способа достижения того же результата — это использовать (множественное?) Наследование или установить флаг в объекте и написать много ifs. Первый вариант быстро выходит из строя, если у вас есть несколько политик, таких как хранилище, владелец и т. Д. Второй вариант приводит к не поддерживаемому коду.
Таким образом, если вашему классу нужно много ортогональных движущихся частей, дизайн на основе политики будет хорошим выбором, и он будет гораздо более масштабируемым, чем другие подходы.
Тем не менее, ваш пример на самом деле не нуждается в таком подходе. Доступ кажется неотъемлемой частью этого: если вы собираетесь позвонить hasAccess()
в любом случае в своем коде вы можете смело заменять его логической переменной.