Имейте метод, который может использоваться только уникальным типом класса - PullRequest
1 голос
/ 21 января 2012

В настоящее время я ищу правильный способ ограничить использование метода определенным типом класса. Чтобы быть более понятным, вот ситуация:

У меня есть класс, посвященный работе в сети на сервере (назовем его ClientSession). У клиента, подключенного к серверу, есть 30 секунд для аутентификации, или сервер закроет соединение.

Аутентификация обрабатывается другим классом на сервере (назовем его Authenticator), который должен будет «предупредить» ClientSession, что клиент успешно прошел аутентификацию и 30-секундный таймер можно отменить.

Проблема в том, что для вызова открытого метода ClientSession потребуется Authenticator. Но я не хочу, чтобы этот метод мог быть вызван кем-либо.

Подводя итог, я хочу, чтобы Authenticator был единственным классом, способным вызвать метод ClientSession::clientAuthSuccessful().

Я рассмотрел две вещи:

  • Методы Friend, но я не хочу, чтобы Authenticator имел доступ ко всем закрытым методам и свойствам или ClientSession через метод Friend.
  • Шаблон дизайна посетителя, но он, кажется, не выполняет именно то, что я хочу (если я неправильно понял его использование).

Есть ли другой способ иметь такие конкретные ограничения? Или чистая альтернатива?

Ответы [ 5 ]

2 голосов
/ 22 января 2012

Определить интерфейс, AuthenticatorListener, с определенным в нем методом clientAuthSuccessful() (как чисто виртуальный).

Сделать ClientSession наследуемым от AuthenticatorListener конфиденциально и реализовать метод (конфиденциально).

Затем экземпляр ClientSession передает себя в Authenticator.

Теперь ни один другой класс не может получить доступ к методу.И Authenticator не связан с ClientSession, только с соответствующим разделенным интерфейсом.

1 голос
/ 21 января 2012

Есть намного более простой способ. Просто передайте какой-то специальный код из ClientSession в Authenticator. Вы можете достичь этого, используя указатель на функцию, функциональный объект или лямбда-функцию.

class ClientSession
{
public:
    void startSession ( Authenticator& authenticator )
    {
        // pass function pointer to method to call when
        // the timeout for authentication has elapsed.
        authenticator.start(this, &ClientSession::warnThat30SecsHasPassed);

        // alternative syntax, using new lambda function syntax,
        // which will end up reducing coupling between the two classes.
        authenticator.start([this](){ warnThat30SecsHasPassed() });
    }
private:
    void warnThat30SecsHasPassed () { ... }
};

class Authenticator
{
public:
    // classic way.
    void start ( ClientSession * session, void(ClientSession::*callback)() );

    // using new syntax.
    void start ( std::function<void()> callback );
}
1 голос
/ 21 января 2012

Нет чистого способа сделать это, нет.Вы либо используете классы друзей, либо открытые методы.

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

class Lock
{
    friend class B;
private:
    Lock() {};
};


class A
{
public:
    A() {}
    void foo(Lock x){}
};

class B
{
    void foo()
    {
        Lock l;
        A a;
        a.foo(l);
    }
};

Поскольку class B - единственный класс, который может создавать Lock экземпляров, а A::fooв качестве параметра требуется экземпляр Lock, он может быть вызван только B.

Не делайте этого, хотя.Я бы предложил добавить комментарии и документацию к заголовкам.

0 голосов
/ 21 января 2012

Когда сталкиваешься с проблемой, часто приходит идея о том, как ее решить, и мы тратим наши усилия на то, как реализовать это решение. Иногда лучше вернуться к проблеме и подумать о других решениях.

Например, вместо того, чтобы Authenticator пытаться уведомить ClientSession, который был передан в него (или, что еще лучше, вызывая какой-то обратный вызов , переданный в него), как насчет того, чтобы позволить ClientSession (или какой-либо другой объект / поток) вызывает метод, подобный Authenticator::waitForAuthentication(int timeout)?


Редактировать: Я думал, что уточню понятие callback . Дело в том, что Authenticator не нужно знание класса ClientSession, чтобы выполнять свою работу; ему просто нужно знать, чтобы вызвать какую-либо функцию или другую вызываемую функцию.

Итак, вы пишете свой Authenticator, чтобы иметь метод, который принимает некоторый std::function объект с правильной подписью, и ClientSession (или любой другой) создает подходящую вещь для передачи. Это может быть специализированная функция объект похож на то, что предлагает Лучиан Григоре. Может быть, это немного более общий объект, или, может быть, тот, который инициализируется ссылками на приватные части вашего ClientSession объекта. Или это лямбда, если вы можете использовать C ++ 11.

Тем не менее, я подозреваю, что метод waitForAuthentication (или что-то еще полностью) вполне может быть тем, что вы действительно хотите для своего приложения.

0 голосов
/ 21 января 2012

Вы можете создать прокси-класс, который ClientSession друзей и друзей Authenticator.

...