【问题标题】:Accessing private implementation member without exposing them (C++)访问私有实现成员而不暴露它们(C++)
【发布时间】:2016-03-05 15:16:55
【问题描述】:

我有两个类,Repository 和 Search。 Repository 封装了存储和管理内容的逻辑,Search 封装了搜索内容的逻辑,还需要访问 Repository 对象才能读取内容。

一般来说,我想将 Repository 类的功能分为公共的,该类的每个用户都可以访问,以及私有的,它们应该只在内部可用。我遇到的问题是 Search 类应该可以访问 Repository 的私有功能,但是因为 Repository 对象将从外部传递给 Search 对象,所以它只会公开公共功能。

我现在这样做的方式是,Repository 使用 pimpl idiom 来隐藏实现细节,并且我将 Search 声明为朋友,因此它可以在实现代码中使用私有功能。

Repository.h:

// Forward declaration of implementation class
class RepositoryImpl;

// Forward declaration of friend class
class Search;

class Repository
{
public:
   // public interface

private:
   RepositoryImpl* pImpl;
};

搜索.h

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

搜索.cpp

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

这显然只是给出和想法,所以它在实际功能方面没有任何意义,但我希望它能够很好地解释我正在努力解决的问题。 有人可能会说在这里使用friend 非常好,但对我来说感觉有点“hacky”,所以如果有更好的方法(一些设计模式)来解决它,我想使用。

我也不想将这些类合并为一个(尽管这似乎是个好主意),因为它引入了某些不可接受的限制。基本上我希望能够拥有一个搜索引擎,能够使用多个存储库。如果允许以干净的方式实现目标,我愿意完成对类的重新设计。

非常感谢您。

【问题讨论】:

  • 为什么不将 someHiddenMethod 设为公开并从公共界面访问它?
  • 使Search 成为friendRepository 绝对是hackish。这是Repositorypublic 接口不足的症状。我认为在public 接口中提供对Repository所有内容 的访问会更好。那么就不需要将friendship 授予Search
  • qqww2 someHiddenMethod 基本上允许从存储库中检索一些我不想让用户使用的信息。至少不是直接的。

标签: c++ design-patterns implementation friend


【解决方案1】:

您可以创建一个接口,例如SearchableSearch 使用该接口,RepositoryImpl 实现该接口。然后,向Repository 添加一个公共接口,该接口返回pImpl 成员,但缩小为Searchable 接口。

执行上述操作的好处是您不必将RepositoryImpl 的所有实现细节暴露给Search,这让您的方法感觉像是一个hack。

// 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();
}

【讨论】:

  • 您的解决方案基本上是最初所做的。为了解释为什么它不是一个好的解决方案,我将尝试更好地描述这个问题。当内容被放入存储库时,它被分成块,但用户对此一无所知。当他们请求数据时,他们将数据整合在一起,并在后台进行合并(如果需要)。搜索算法需要访问这些块,这是作为私有方法实现的。如果我暴露了接口,我也会暴露底层结构的信息,这是我不想做的。 [下文继续]
  • 我正在考虑向前声明 Searchable,因此可以将指针传递给 Search 类,而无需透露它的作用,但对我来说,它感觉比使用朋友更不优雅,因为我将指针暴露给不完整类型。
  • 暴露Search所需的组件正是Searchable的工作。注意Searchable 的方法是私有的,只能被它的朋友Search 访问。
【解决方案2】:

您可能不需要访问存储库实现详细信息。

搜索应该能够在 Repository 上工作,而无需了解任何有关 Repository 的详细信息,例如您是否使用 STL 容器及其元素的迭代器。

因此,您可能应该修改 Repository 接口以授予对底层元素的访问权限(例如将 begin() 和 end() 添加到公共接口)并让 Search 类使用这些“句柄”。 如果搜索功能足够通用,可以与其他类型的“迭代器”一起使用,那就更好了。

附:我更愿意将此作为评论添加,因为这些信息并不准确,无法给出明确的答案。但我不被允许,因为我的名声不好。

【讨论】:

  • 正如我在对评论的回复中提到的,RepositoryImpl 允许直接访问一些非常具体的信息,我绝对不想让用户访问它们。搜索类仅在内部需要它们,以便执行更复杂的算法。我很欣赏你所说的,Repository 公共接口应该足以满足任何使用它的需求,但在当前状态下,它需要从根本上重新实现这两个类,而我目前无法承受。
猜你喜欢
  • 2011-12-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-12-04
  • 1970-01-01
  • 2012-12-20
  • 2012-05-03
相关资源
最近更新 更多