如何合理设计图书馆的外部访问而不干扰其内部访问

How to properly design library external access without mess up its internal access?

本文关键字:访问 干扰 内部 外部 图书馆      更新时间:2023-10-16

我正在尝试设计一个库,只向调用者开放几个接口,而不会弄乱自己的内部访问控制。正确的做法是什么?

例如,下面是库:

namespace ControlledLib {
    class ThinkTrack1   {
        friend class DeepThought;
        friend class ThinkTrack2;
    private:
        int ResultA()   { return 6; }
        int ResultB()   { return 5; }
    };
    class ThinkTrack2   {
        friend class DeepThought;
    private:
        int ResultC()   { ThinkTrack1 tt1; return tt1.ResultB() + 2; }
    };
    class DeepThought   {
        friend int DeepThoughtAnswers();
    private:
        int Answers()   { 
            ThinkTrack1 tt1;
            ThinkTrack2 tt2;
            return tt1.ResultA() * tt2.ResultC(); 
        }
        int CreateWorld()   {
            return 7;
        }
    };
    int DeepThoughtAnswers()    { DeepThought dt;  return dt.Answers(); }
}

,它可以通过

调用
#include "ControlledLib.h"
int i = ControlledLib::DeepThoughtAnswers();

实际的答案是由class DeepThought的函数Answers()给出的,然而,为了使外部调用者只能访问一个Answers(),我必须使class DeepThought的函数私有,并创建一个全局函数DeepThoughtAnswers()作为入口点,它调用class DeepThought来获得答案,然后class DeepThought必须将DeepThoughtAnswers()定义为朋友函数。

才刚刚开始。因为class DeepThought实际上调用class ThinkTrack1class ThinkTrack2, class ThinkTrack2调用class ThinkTrack1等等…为了使所有这些外部调用者无法访问,所有这些函数都被设置为private,并且我必须定义许多friendship。最重要的是,所有这些都搞乱了内部访问控制!

有什么更好的方法吗?

在设计界面时,您可以从中选择一些选项。第一种方法是只定义一个导出一组函数的C接口。这些函数在内部调用你的类,这些类隐藏在这一层中。

<ControlledLib.h>
extern "C" int DeepThoughAnswers();
</ControlledLib.h>

在源文件中,你有这个函数的实现:

<ControlledLib.cpp>
#include "DeepThought.h"
#include "ThinkTrack1.h"
#include "ThinkTrack2.h"
int DeepThoughAnswers()
{
     DeepThought dt;
     return dt.Answers();
}
</ControlledLib.cpp>

您在此源代码中包含的文件然后使用不含friend的可见性,并且您只发布结果库和ControlledLib.h文件。

另一种方法是使用c++接口隐藏实现细节。接口来了:

<ControlledLib.h>
class ControlledLib
{
public:
    virtual int DeepThoughAnswers() = 0;
};
</ControlledLib.h>

那么你就有了这个接口的实现,它看起来像这样:

<MyControlledLib.h>
class MyControlledLib : public ControlledLib
{
public:
    virtual int DeepThoughAnswers();
    void someOtherFunction(); //<-- not visible to the 'outside'
};
</MyControlledLib.h>

此外,您添加了一个工厂,允许客户端实例化您的库。

<ControlledLib.h>
#include "ControlledLib.h"
class MyControlledLibFactory
{
public:
    static MyControlledLib* create();
};
</MyControlledLib.h>

对于客户端,您只发送工厂和接口,其他一切都是隐藏的。到目前为止,您的接口只使用基本类型,这意味着您不必导出任何其他内容。如果希望在接口中使用类,还需要导出这些类以供使用。

<ControlledLib.h>
class ControlledLib
{
public:
    virtual int DeepThoughAnswers() = 0;
    virtual ComplexAnswer* DeepThoughAnswersAreComplex() = 0; //<-- ComplexAnswer header needs to be supplied too.
};
</ControlledLib.h>

我建议你使用更多受保护的关键字,减少朋友关键字的使用,重新设计界面,因为它看起来很乱。实现和接口的桥接设计模式将是很好的,您可以将实现隐藏为库,并将接口仅作为头文件分发。