Представление класса, который делает следующее
class AClass
{
AClass() : mode(0) {}
void a()
{
if (mode != 0) throw ("Error mode should be 0");
// we pass the test, so now do something
...
mode = 1;
}
void b()
{
if (mode != 1) throw("Error mode should be 1");
// we pass the test, so now do something
...
}
int mode;
};
Класс содержит много методов (более 20), и для каждого из этих методов нам нужно проверить значение режима, что, очевидно, является большим дублированием кода. Кроме того, мы можем выделить две категории методов: тех, кто выдает ошибку, если mode! = 0, и тех, кто выдает ошибку, если mode! = 1. Можно ли как-то сгруппировать эти методы в две категории (категория A = метод, который выдает ошибку, если mode! = 0) и категория B для метода, который выдает ошибку, если mode! = 1)?
РЕДАКТИРОВАТЬГлядя на текущие ответы, я понимаю, как я формулирую вопрос, и проблема, вероятно, недостаточно ясна. Чего я хочу избежать, так это вызывать функцию в каждом методе класса. Пишем ли мы код в начале методов или помещаем этот код в функцию и вызываем эту функцию — это не проблема. Вопрос в том, сможем ли мы избежать всего этого вместе. Есть ли методика, которая поможет автоматически проверять, является ли вызов метода класса действительным в зависимости от некоторого контекста.
AClass на самом деле API в контексте моего проекта. a (), b () и т. д. — это некоторые функции, которые программист может вызывать, если он / она хочет использовать API, однако некоторые из этих методов могут вызываться только в определенном порядке. Например, вы можете видеть в коде, что a () устанавливает mode = 1. Таким образом, программист может сделать что-то вроде этого:
a(); // mode = 0 so it's good
b(); // mode = 1 so it's good
но этот код должен потерпеть неудачу (он, конечно, скомпилируется, но во время выполнения мне нужно выдать ошибку, указав, что контекст, в котором был вызван b (), был неправильным).
b(); // mode 0 so it won't work
a(); // it will compile but throw an exception
Я пытался выяснить, может ли какой-либо шаблон работать для этого, но ничего не смог найти. Это кажется мне невозможным, и я считаю, что единственный вариант — написать необходимый код. Может ли кто-нибудь предложить что-нибудь? Большое спасибо.
Просто добавьте приватные функции-члены:
void assert_mode_0() {
assert_mode(0);
}
void assert_mode_1() {
assert_mode(1);
}
void assert_mode(int m) {
if (mode != m)
throw msg[m];
}
с подходящим определением msg
, конечно.
Помимо реализации проверки в специальном методе (отличное предложение), вы также можете рассмотреть возможность декомпозиции поведения в AClass
на два отдельных класса или делегировать конкретную часть новой паре классов. Это кажется особенно уместным, если mode
инвариантен для экземпляра (как в примере).
Ну, я думаю, простейшим решением было бы определение макроса или некоторой встроенной функции, например:
#define checkErrorMode0(x) \
if ((x) != 0) throw ("Error mode should be 0");
#define checkErrorMode1(x) \
if ((x) != 1) throw ("Error mode should be 1");
// or, probably within your class
inline void checkErrorMode0(int x){
if ( x != 0 ) throw ("Error mode should be 0");
}
inline void checkErrorMode1(int x){
if ( x != 1 ) throw ("Error mode should be 1");
}
Таким образом, вы можете просто вызвать один из этих методов внутри функций, которые их требуют.
Но, скорее всего, есть более элегантный обходной путь для того, что вы хотите сделать.
После более подробного изучения проблемы кажется, что ближайший полезный ответ (Ник):
Попробуйте заглянуть в Аспектно-ориентированную разработку программного обеспечения en.wikipedia.org/wiki/Aspect-oriented_software_development — Ник
Страницу Википедии нелегко читать, и она не содержит пример C ++, поэтому сначала она остается очень абстрактной, но если вы ищете Аспектно-ориентированное программирование и C ++, вы найдете ссылки с примерами.
Идея, стоящая за этим (и это просто очень краткое резюме), состоит в том, чтобы найти способ добавления «сервисов» или «функциональных возможностей» к классу. Эти сервисы могут быть добавлены во время компиляции с помощью шаблонов. Это то, с чем я интуитивно экспериментировал, пытаясь решить мою проблему, и я рад видеть, что эта техника существует уже много лет.
Этот документ является хорошей ссылкой:
Аспектно-ориентированное программирование & C ++ Кристофер Диггинс, 1 августа 2004 г.
И я нашел эту ссылку с примером полезной для понимания концепции:
Реализация аспектов с использованием генеративного программирования от Calum Grant.