2015-12-01 2 views
1

У меня есть два класса: репозиторий и поиск. Репозиторий инкапсулирует логику для хранения и управления контентом, а Search инкапсулирует логику для поиска по содержимому, а также требует доступа к объекту репозитория, чтобы читать содержимое.Доступ к частному элементу реализации, не подвергая его воздействию (C++)

Как правило, я хочу разделить функциональность класса репозитория на общедоступную, что каждый пользователь класса будет иметь доступ к частному и должен быть доступен только внутри страны. Проблема заключается в том, что класс поиска должен иметь доступ к частной функции репозитория, но поскольку объект репозитория будет передан объекту поиска извне, он будет публиковать только общедоступные функции.

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

Repository.h:

// Forward declaration of implementation class 
class RepositoryImpl; 

// Forward declaration of friend class 
class Search; 

class Repository 
{ 
public: 
    // public interface 

private: 
    RepositoryImpl* pImpl; 
}; 

search.h

class Search 
{ 
public: 
    void searchRepository(Repository* repo); 
}; 

Search.cpp

void Search::searchRepository(Repository* repo) 
{ 
    repo->pImpl->someHiddenMethod(); 
} 

Это, очевидно, просто чтобы дать и идея, так что не имеет никакого смысла с точки зрения реальной функциональности, но я надеюсь, что это хорошо объясняет, с чем я борюсь. Некоторые могут сказать, что использование друга здесь отлично, но для меня это немного «взломано», поэтому, если есть лучший способ (какой-то шаблон дизайна), чтобы обойти его, я бы хотел использовать.

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

спасибо, что заранее.

+2

Почему бы не сделать этот 'someHiddenMethod' общедоступным и просто получить доступ к нему из открытого интерфейса? –

+1

Создание 'Поиск'' '' '' 'Репозитория' определенно хакерское. Это признак неадекватного «публичного» интерфейса «Репозитория». Я думаю, что лучше будет предоставлять доступ к * содержимому * 'Repository' в' public' интерфейсе. Тогда не будет необходимости предоставлять 'friend' '' Search'. –

+0

https://stackoverflow.com/questions/12048193/why-is-it-legal-to-inappropriately-access-privates-in-an-explicit-instantiation – David

ответ

0

Возможно, вам не нужно иметь доступ к деталям реализации репозитория.

Поиск должен иметь возможность работать с репозиторием, не зная о деталях репозитория, как если бы вы использовали контейнер STL и итераторы для своих элементов.

Возможно, вам необходимо изменить интерфейс репозитория, чтобы предоставить доступ к базовым элементам (например, добавить открытый() и end() в открытый интерфейс) и позволить классу Search работать с этими «ручками». Лучше, если поиск может быть достаточно общим для работы с другими «итераторами».

P.S. Я бы предпочел добавить это как комментарий, потому что информация не так точна, чтобы дать окончательный ответ. Но мне не разрешено из-за моей низкой репутации.

+0

, как я упоминал в ответе на комментарий, RepositoryImpl позволяет получить доступ к некоторой очень конкретной информации напрямую, и я определенно не хочу, чтобы пользователь обращался к ним. Класс поиска требует их только внутри, для выполнения более сложных алгоритмов. Я ценю то, что вы говорите, что открытый публичный интерфейс хранилища должен быть достаточным для чего-либо, использующего его, но в текущем состоянии потребовалось бы перепрофилировать оба класса по существу, чего я не могу себе позволить в данный момент. – zedsdead

2

Вы можете создать интерфейс, скажем Searchable, который использует Search и что RepositoryImpl реализует. Затем добавьте открытый интерфейс к Repository, который возвращает член pImpl, но сужается до интерфейса Searchable.

Преимущество этого заключается в том, что вам не нужно раскрывать все детали реализации от RepositoryImpl до Search, что делает ваш подход похожим на хак.

// in Search.h 
class Searchable 
{ 
    friend class Search; 
    virtual void internal_method() = 0; 
    //... 
protected: 
    virtual ~Searchable() = default; 
}; 

// in Repository.cpp 
class RepositoryImpl : public Searchable //... 
{ 
    //... 
}; 

Searchable * Repository::searchable() { return pImpl; } 

// in Search.cpp 
void Search::searchRepository(Repository* repo) 
{ 
    repo->searchable()->internal_method(); 
} 
+0

Ваше решение - это в основном то, что было сделано на начальном этапе. Чтобы объяснить, почему это не было хорошим решением, я попытаюсь немного описать проблему. Когда содержимое помещается в репозиторий, оно делится на куски, но пользователь ничего не знает об этом. Когда они запрашивают данные, они получают его в один кусок, и слияние происходит (если требуется) за сценой. Алгоритм поиска требует доступа к этим фрагментам, которые реализуются как частные методы. Если я открою интерфейс, я также выложу информацию о базовой структуре, которую я не хочу делать. [продолжение ниже] – zedsdead

+0

Я рассматривал возможность переадресации поиска Searchable, поэтому указатель может быть передан классу Search, не раскрывая, что он делает, но для меня он чувствует себя еще менее изящным, чем использование друга, поскольку я выставляю указатель на неполный тип. – zedsdead

+0

Выявление компонентов, требуемых 'Поиск', - это точно задание' Searchable'. Обратите внимание, что методы 'Searchable' являются частными и могут быть доступны только его другу' Search'. – jxh

Смежные вопросы