【问题标题】:API design: Best way to hide data model object from user?API 设计:向用户隐藏数据模型对象的最佳方式?
【发布时间】:2014-08-28 01:18:49
【问题描述】:

我正在使用 C++ 编写一个简单的 API,在该 API 中,我的代码的最终用户会将 UserProfile 类的实例传递给其他各种类进行修改。用户配置文件有一个非常基本的公共接口,数据存储在一个私有 pimpl 对象中。然后我将实现类添加为朋友,以便他们可以访问在单独的实现文件中定义的内部数据结构。此类的基本大纲如下所示。 . .

// For pimpl here
class UserProfileData;

class UserProfile
{
public:
    /// ctor to allocate impl
    UserProfile();

    /// dtor 
    ~UserProfile();

    /// Do some very simple stuff with a few methods
    std::string getProfileName() const;

private:
    /// Use pimpl and hide impl so API user can just use simplified interface
    std::unique_ptr<UserProfileData> userProfileData;

    /// Allow implementation classes access to userProfileData
    friend class ClassOne;
    friend class ClassTwo;
};

构建一个庞大的朋友类列表并不是向 API 用户隐藏数据的最优雅的解决方案。好像有点臭。是否有任何模式或习语可以让我以不同的方式实现相同的目标?

【问题讨论】:

  • 大多数时候,ClassOneClassTwo 需要的任何东西都应该是 public。您自己就是您的 API 的用户。
  • 这里没有足够的细节来选择各种选项。例如,为什么不只为 userProfileData 提供一个公共访问器函数,而只为不应访问的人保留未定义的 UserProfileData 呢?你想阻止什么用例?

标签: c++ design-patterns architecture idioms


【解决方案1】:

想一想通过隐藏UserProfile 类的实现细节来尝试实现什么。从它的声音来看,您可能正在努力将消费者与数据的内部结构分离。但是,使用数据容器执行此操作可能麻烦多于其价值。

纯粹从消费者的角度来看,没有必要像这样隐藏类的细节。考虑以下数据类型:

    struct ProfileData
    {
        std::string profileName;
    }

    struct ProfileDataWithHiddenDetails
    {
        std::string getProfileName();
    }

每种类型的用途都很简单:它们用于在相关方之间传输个人资料信息。每种类型都非常适合此目的,但其中一种比另一种更易于推理。

getProfileName 是否与数据库通信?它是否从更深层次的值中检索配置文件名称?配置文件名称是否仅存储在成员变量中?任何这些(除其他外)都是可能的;该信息已被故意向消费者隐藏。

第一个问题是:这些信息需要对消费者隐藏吗?如果消费者将对象用作数据容器,那么抽象只会得到在路上。

如果您的意图确实是隐藏数据结构的细节,那么下一个问题是:您需要向消费者隐藏哪些信息如果对象是不是一个简单的数据聚合器,消费者在使用它时需要采用不同的思维方式。

抽象可以让推理系统变得更容易,但也可以让推理变得更难。尝试在您的 API 中抽象行为而不是数据


示例

想象一下ProfileDataWithHiddenDetails::getProfileName 实际上是从您希望对消费者隐藏的丰富对象模型中检索配置文件名称。比如:

    std::string getProfileName
    {
        return objectModel.getRoot().getUserProfile().profileName;
    }

这些细节不需要在getProfileName的实现中隐藏。也许有一个 API 函数调用返回了配置文件数据:

    ProfileDataWithHiddenDetails getProfileData()
    {
        return ProfileDataWithHiddenDetails(objectModel);
    }

这个 API 函数可以自己处理抽象,而不是返回抽象:

    ProfileData getProfileData()
    {
        auto profileName = objectModel.getRoot().getUserProfile().profileName;

        return ProfileData { profileName };
    }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-01-28
    • 2016-09-02
    • 1970-01-01
    • 2017-11-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多