如何为现有代码库创建公共API? [英] How to create a public API for an existing codebase?

查看:107
本文介绍了如何为现有代码库创建公共API?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图为用C ++编写的私有代码库创建一个公共C ++ API。我试着这样做:




  • 为每个私人类创建一个包装API类。

  • 有一个公共的API基类,它有一个指向私有类的指针。

  • API类实现不包含任何功能,只是将方法调用转发给它们的私有对象。 li>


这似乎是一个合理的方法。然而,在现实中,它很快导致非常笨拙的代码。这是一个代表我遇到的问题的示例。



(编辑:代码也可以查看此处)。




私有API类(这里没有问题)

 命名空间核心{


//所有Core类的基类。
class CoreObject
{
public:
virtual〜CoreObject();
};

类接口;
class Stream;

类服务器:public CoreObject
{
public:
Interface * createInterface();

private:
std :: vector< Interface *> mInterfaces;

};

类接口:public CoreObject
{
public:
void addStream(Stream * stream);

const Stream * getStreamByIndex(std :: size_t index)const;

std :: size_t streamCount()const;

private:
std :: vector< Stream *> mStreams;
};

class Stream:public CoreObject
{
public:
void start();

void stop();

private:
std :: string mStats;
};


} //核心


公共API类声明(到目前为止很好)

 命名空间Core {
class CoreObject;
}


命名空间API {


class APIStream;
class APIInterface;

//所有API类的基类。
class APIObject
{
public:
APIObject(Core :: CoreObject * inCoreObject);

virtual〜APIObject();

Core :: CoreObject * getCoreObject();

const Core :: CoreObject * getCoreObject()const;

void setCoreObject(Core :: CoreObject * inCoreObject);

private:
Core :: CoreObject * mCoreObject;
};

class APIServer:public APIObject
{
public:
APIServer();

APIInterface * createInterface();
};

class APIInterface:public APIObject
{
public:
APIInterface();

void addStream(APIStream * stream);

const APIStream * getStreamByIndex(std :: size_t index)const;

APIStream * getStreamByIndex(std :: size_t index);

std :: size_t streamCount()const;
};

class APIStream:public APIObject
{
public:
APIStream();

void start();

void stop();
};




API实作(太多投放,通常笨拙)

  #includeAPI.h
#includeCore.h


命名空间API {


APIObject :: APIObject(Core :: CoreObject * inCoreObject):
mCoreObject(inCoreObject)
{
}

APIObject ::〜APIObject()
{
}

Core :: CoreObject * APIObject :: getCoreObject()
{
return mCoreObject;
}


const Core :: CoreObject * APIObject :: getCoreObject()const
{
return mCoreObject;
}


void APIObject :: setCoreObject(Core :: CoreObject * inCoreObject)
{
mCoreObject = inCoreObject;
}


//
// APIServer
//
APIServer :: APIServer():
APIObject Core :: Server)
{
}

APIInterface * APIServer :: createInterface()
{
Core :: Server * coreServer = static_cast< Core :: Server *>(getCoreObject());
Core :: Interface * coreInterface = coreServer-> createInterface();
APIInterface * result(new API :: APIInterface);
result-> setCoreObject(coreInterface);
return result;
}


//
// APIInterface
//
APIInterface :: APIInterface():
APIObject Core :: Interface)
{
}

void APIInterface :: addStream(APIStream * apiStream)
{
Core :: Stream * coreStream = static_cast< ; Core :: Stream *>(apiStream-> getCoreObject());
Core :: Interface * coreInterface = static_cast< Core :: Interface *>(getCoreObject());
coreInterface-> addStream(coreStream);
}


//
// APIStream
//
const APIStream * APIInterface :: getStreamByIndex(std :: size_t index) const
{
const Core :: Interface * coreInterface = static_cast< const Core :: Interface *>(getCoreObject());
const Core :: Stream * coreStream = coreInterface-> getStreamByIndex(index);

//现在我如何获得APIStream对象?
return 0;
}

std :: size_t APIInterface :: streamCount()const
{
const Core :: Interface * coreInterface = static_cast< const Core :: Interface * ;(getCoreObject());
return coreInterface-> streamCount();
}

APIStream :: APIStream():
APIObject(new Core :: Stream)
{
}

void APIStream :: start()
{
static_cast< Core :: Stream *>(getCoreObject()) - > start
}

void APIStream :: stop()
{
static_cast< Core :: Stream *>(getCoreObject()) - > stop
}

} // API



你可以看到实现看起来不太好。非常感谢您对这些问题的解答或见解:




  • 我在哪里错了?






更新

工作真的很好。您可以在改进代码中看到,所有问题都解决了。



我仍然需要将这个解决方案应用于明天的实际代码。

解决方案

当这样做的时候,有更多或更少的API和实现对象之间的一对一关系,我通常会使用静态工厂方法< a>,并且具有从API类派生的实现类。像这样:



file:api.h



  b $ b {
public:
static Interface * Create();
virtual void Foo()= 0;
};



档案:impl.h



  class Concrete:public Interface 
{
public:
void Foo(){};
};



file:impl.cpp



  Interface * Interface :: Create()
{
return new Concrete;
}

这有很多好处。包括:


  1. 创建可以构造许多不同的实现,

  2. 返回类型依赖于语言的协方差规则,因此不需要转换。

  3. 调试更容易一些,因为你可以准确地判断出 Interface 是什么样的。


I'm trying to create a public C++ API for a private code base that is also written in C++. I tried to do this as follows:

  • Create a wrapper API class for each private class.
  • Have a common API base class that has a pointer to the private class.
  • The API class implementations don't contain any functionality but simply forward the method calls to their private counterparts.

This seemed like a reasonable approach. However, in reality it quickly results in very clumsy code. Here is an example that represents the problem I'm experiencing.

(Edit: the code can also be viewed here).


The private API classes (no problem here)

namespace Core {


// Base class for all Core classes.
class CoreObject
{
public:
    virtual ~CoreObject();
};    

class Interface;
class Stream;    

class Server : public CoreObject
{
public:
    Interface * createInterface();

private:
    std::vector<Interface*> mInterfaces;

};    

class Interface : public CoreObject
{
public:
    void addStream(Stream * stream);

    const Stream * getStreamByIndex(std::size_t index) const;

    std::size_t streamCount() const;

private:
    std::vector<Stream*> mStreams;
};    

class Stream : public CoreObject
{
public:
    void start();

    void stop();

private:
    std::string mStats;
};


} // Core


The public API class declarations (so far so good)

namespace Core {
class CoreObject;
}


namespace API {


class APIStream;
class APIInterface;    

// Base class for all API classes.
class APIObject
{
public:
    APIObject(Core::CoreObject * inCoreObject);

    virtual ~APIObject();

    Core::CoreObject * getCoreObject();

    const Core::CoreObject * getCoreObject() const;

    void setCoreObject(Core::CoreObject * inCoreObject);

private:
    Core::CoreObject * mCoreObject; 
};    

class APIServer : public APIObject
{
public:
    APIServer();

    APIInterface * createInterface();
};    

class APIInterface : public APIObject
{
public:
    APIInterface();

    void addStream(APIStream * stream);

    const APIStream * getStreamByIndex(std::size_t index) const;

    APIStream * getStreamByIndex(std::size_t index);

    std::size_t streamCount() const;
};    

class APIStream : public APIObject
{
public:
    APIStream();

    void start();

    void stop();
};


The API implementation (too many casts, generally clumsy)

#include "API.h"
#include "Core.h"


namespace API {


APIObject::APIObject(Core::CoreObject * inCoreObject) :
    mCoreObject(inCoreObject)
{
}

APIObject::~APIObject()
{
}

Core::CoreObject * APIObject::getCoreObject()
{
    return mCoreObject;
}


const Core::CoreObject * APIObject::getCoreObject() const
{
    return mCoreObject;
}


void APIObject::setCoreObject(Core::CoreObject * inCoreObject)
{
    mCoreObject = inCoreObject;
}


//
// APIServer
//
APIServer::APIServer() :
    APIObject(new Core::Server)
{
}    

APIInterface * APIServer::createInterface()
{
    Core::Server * coreServer = static_cast<Core::Server*>(getCoreObject());
    Core::Interface * coreInterface = coreServer->createInterface();
    APIInterface * result(new API::APIInterface);
    result->setCoreObject(coreInterface);
    return result;
}


//
// APIInterface
//
APIInterface::APIInterface() :
    APIObject(new Core::Interface)
{
}    

void APIInterface::addStream(APIStream * apiStream)
{
    Core::Stream * coreStream = static_cast<Core::Stream *>(apiStream->getCoreObject());
    Core::Interface * coreInterface = static_cast<Core::Interface*>(getCoreObject());
    coreInterface->addStream(coreStream);
}


//
// APIStream
//
const APIStream * APIInterface::getStreamByIndex(std::size_t index) const
{
    const Core::Interface * coreInterface = static_cast<const Core::Interface*>(getCoreObject());
    const Core::Stream * coreStream = coreInterface->getStreamByIndex(index);

    // Now how I get the the APIStream object?
    return 0;
}

std::size_t APIInterface::streamCount() const
{
    const Core::Interface * coreInterface = static_cast<const Core::Interface*>(getCoreObject());
    return coreInterface->streamCount();
}    

APIStream::APIStream() :
    APIObject(new Core::Stream)
{
}    

void APIStream::start()
{
    static_cast<Core::Stream*>(getCoreObject())->start();
}       

void APIStream::stop()
{
    static_cast<Core::Stream*>(getCoreObject())->stop();
}    

} // API


As you can see the implementation looks doesn't look too good. I would appreciate your answers or insights regarding these questions:

  • Where did I go wrong?
  • What should I have done instead?


Update

John Dibling's suggestion seems to work really well. As you can see in the improved code, all problems are solved neatly.

I still have to apply this solution to the real code at work tomorrow. I'm interested to see how well it works there.

解决方案

When doing this kind of thing, where there is more or less a one-to-one relation between the API and implementation objects, I'll generally use a static factory method, and have the implementation class derive from the API class. Like this:

file: api.h

class Interface
{
public:
  static Interface* Create();
  virtual void Foo() = 0;
};

file: impl.h

class Concrete : public Interface
{
public:
  void Foo() {};
};

file: impl.cpp

Interface* Interface::Create()
{
  return new Concrete;
}

This has a number of benefits. Including:

  1. Create can construct many different implementations, and Interface's ABI doesn't have to change.
  2. The return types rely on the language's covariance rules, so no casts are needed.
  3. Debugging is somewhat easier, because you can tell exactly what kind of Interface you've got.

这篇关于如何为现有代码库创建公共API?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆