如何正确设计库外部访问而不会搞砸其内部访问?

时间:2016-10-20 01:05:51

标签: c++ design-patterns

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

例如,这是库:

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等等...为了让外部调用者无法访问所有这些,所有这些功能设置为私人,我必须定义很多朋友。最重要的是,所有这些都搞砸了内部访问控制!

什么是更好的方法呢?

2 个答案:

答案 0 :(得分:1)

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

答案 1 :(得分:1)

设计界面时,您可以选择一些选项。第一种是只定义一个导出一组函数的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>