I am developing a parser library where i parse data and store it in different data structures. The design of the library is such that it will have a DataProvider, Parser and DataStore class. The DataStore is a memebr of DataProvider class. The consumer needs to call the functions in the DataProvider to parse the file and to retrieve the data from the library.
Now if i expose the DataProvider class then i need to expose the DataStore class also which gives the implementation details to the consumer. What is the alternative way of exposing the functions of the DataProvider class? Should i expose functions like LoadFile, GetRecords and create the DataProvider o开发者_JAVA技巧bject globally inside the cpp?
If the user doesn't have to use the DataStore
directly, it should better not be exposed. You can achieve that by creating an "interface" - abstract DataProvider
with only public pure virtual functions. Internally, have a DataProviderImp
which will inherit from DataProvider
, and contain all the required definitions and members that are part of the actual implementation.
Let the user work only with the abstract class. This way, you drag only the minimal dependencies into your API.
Firstly minimize the information that needs to be disclosed in the headers, so use forward declarations, references and pointers where possible (so only a forward declaration is needed), and try to use a PIMPL idiom to hide the implementation.
Next you could build another class that is a facade to the system, which wraps up the entry points to the functions, and use indirect methods to access contained elements (such as data elements accessible externally), such as handles and indexes.
If the concern is that external users might create their own DataStore
objects, use them outside the context of a DataProvider
, and them complain that your library doesn't work, there is an easy solution and some not so easy solutions.
The easy solution: Document that DataProvider
is the external interface to your library. This is the solution employed in the C++ standard library, and in Boost. The interface to std::map
is the header file <map>
. The implementation files that that header #includes
, and the underlying data types that <map>
and its subsidiary headers create are none of your business. You should only use the std::map
public interfaces. Use internal data types and you're off into the world of undefined behavior. Comments like // The class DataStore is for internal use only. Use it and you will be fired.
can be quite a powerful deterrent.
A solution that does not rely on the above: Wall off those subsidiary classes by defining them inside DataProvider
(e.g., you will have class DataProvider::DataStore
) and making those class definitions private/protected to DataProvider
. Another approach is to make everything in DataStore
private/protected, and make DataProvider
a friend class.
Since you are delivering a static library and headers, there will always be some nasty hackish means to get at your underlying data and methods no matter how hard you try to wall them off. At some point, the "This is for internal use only. Keep your dirty mitts off!" approach has quite a bit of merit.
精彩评论