[Newbie] Design problem, code organization - advice needed

S

SpOiLeR

Hi everybody.

My problem is this. I have 4 different text file formats which basically
contain same data differently formated. I have class ParsedData which
handles data from this files. I also have 4 parses which can read from
files into ParsedData. Parsers should never be called explicitly (they
should only be called from ParsedData ctor). What is the best way to
protect those parsers? This is what I came up to so far:

1.
Most obvious way is to put all parser methods into private part of the
ParsedData. But... Each parser has its own helper methods (roughly cca. 20
per parser) which are in no way related to ParsedData class and don't touch
any of the ParsedData data members. It doesn't seem logical to put them
into ParsedData interface. Where to put their declarations? I was thinking
of putting their declarations directly into source file of each given
parser so they remain hidden from class interface making interface a *lot*
more tidy and readable. How good is this from the point of code
maintability? Is it a good coding practice? I must mention that I don't
care if user sees this methods exposed, I just want to make ParsedData
interface clearer.

2.
As each parser is a "class" of methods on their own I thought encapsulating
each one into it's own class and pronounce those classes friends to
ParsedData. But this way, they are not protected any more and can be called
independently of ParsedData objects which is exactly the thing I want to
avoid.

I am doing all this because I started learning language a month ago and
wanted to do some coding to get used to basic syntax and std library
features learnt so far. So please bear in mind that I'm quite a newbie in
C++ (with a few years of experience in C programming). TIA
 
D

davidrubin

SpOiLeR said:
Hi everybody.

My problem is this. I have 4 different text file formats which basically
contain same data differently formated. I have class ParsedData which
handles data from this files. I also have 4 parses which can read from
files into ParsedData. Parsers should never be called explicitly (they
should only be called from ParsedData ctor). What is the best way to
protect those parsers? This is what I came up to so far:

You basically have one internal data representation (ParsedData), and
four file formats. You also have four utilities (parsers) that
translate from each of the file formats to the single ParsedData type.

You definitely *do* *not* want to "hide" the parser interfaces from the
user. These should be part of a public API. This way you can test them
independently of the client code which uses the parsers. Also, they can
be re-used.

My suggestion is to have either a) four parser components for each
format which depend only on the 'ParsedData' type, or b) one component,
parseddatautil, which defines a namespace ParsedDataUtil containing
static functions that implement each of the four parsers. (BTW, you
should pick a name that identifies the data, like TradeDate or
NetworkConfiguration, or whatever, rather than "Parsed" Data.)
1.
Most obvious way is to put all parser methods into private part of the
ParsedData. But... Each parser has its own helper methods (roughly cca. 20
per parser) which are in no way related to ParsedData class and don't touch
any of the ParsedData data members. It doesn't seem logical to put them
into ParsedData interface. Where to put their declarations? I was thinking
of putting their declarations directly into source file of each given
parser so they remain hidden from class interface making interface a *lot*
more tidy and readable. How good is this from the point of code
maintability? Is it a good coding practice? I must mention that I don't
care if user sees this methods exposed, I just want to make ParsedData
interface clearer.

Putting these helper functions in an unnamed namespace within the .cpp
file is fine as long as they don't need to access any private member
data. Even then, you may be able to pass these as parameters to the
helper functions.
2.
As each parser is a "class" of methods on their own I thought encapsulating
each one into it's own class and pronounce those classes friends to
ParsedData. But this way, they are not protected any more and can be called
independently of ParsedData objects which is exactly the thing I want to
avoid.

ParsedData sounds like a value-semantic type (it represents a value
rather than a mechanism), in which case it defines a get/set interface
for each data member, plus a copy constructor, and an assignment
operator. In this case, there is no reason for parser classes to be
friends of ParsedData. They can just use the public interface of
ParsedData.
I am doing all this because I started learning language a month ago and
wanted to do some coding to get used to basic syntax and std library
features learnt so far. So please bear in mind that I'm quite a newbie in
C++ (with a few years of experience in C programming). TIA

Keep asking questions. /david
 
V

Victor Bazarov

SpOiLeR said:
My problem is this. I have 4 different text file formats which basically
contain same data differently formated. I have class ParsedData which
handles data from this files. I also have 4 parses which can read from
files into ParsedData. Parsers should never be called explicitly (they
should only be called from ParsedData ctor). What is the best way to
protect those parsers? This is what I came up to so far:

1.
Most obvious way is to put all parser methods into private part of the
ParsedData. But... Each parser has its own helper methods (roughly cca. 20
per parser) which are in no way related to ParsedData class and don't
touch
any of the ParsedData data members. It doesn't seem logical to put them
into ParsedData interface. Where to put their declarations? I was thinking
of putting their declarations directly into source file of each given
parser so they remain hidden from class interface making interface a *lot*
more tidy and readable. How good is this from the point of code
maintability? Is it a good coding practice? I must mention that I don't
care if user sees this methods exposed, I just want to make ParsedData
interface clearer.

2.
As each parser is a "class" of methods on their own I thought
encapsulating
each one into it's own class and pronounce those classes friends to
ParsedData. But this way, they are not protected any more and can be
called
independently of ParsedData objects which is exactly the thing I want to
avoid.

I am doing all this because I started learning language a month ago and
wanted to do some coding to get used to basic syntax and std library
features learnt so far. So please bear in mind that I'm quite a newbie in
C++ (with a few years of experience in C programming). TIA

It would seem reasonable to keep some kind of common interface to your
parsers. That's their base class. Now, if nobody else except your
ParsedData class is going to use those parsers, it would make sense to
define your parsers' base class as a member of the ParsedData:

class ParsedData
{
public:
class Parser
{
public:
/* necessary common methods */
virtual ~Parser() {}
};

ParsedData() {
// creates the necessary parser (possibly by using
// some kind of factory) and uses the common methods
// to parse
}
};

class ParserOne : public ParsedData::parser
{
/* all additional member functions */
/* necessary methods */
};

class ParserTwo : public ParsedData::parser
{
/* all additional member functions */
/* necessary methods */
};

....

V
 
S

SpOiLeR

It would seem reasonable to keep some kind of common interface to your
parsers. That's their base class. Now, if nobody else except your
ParsedData class is going to use those parsers, it would make sense to
define your parsers' base class as a member of the ParsedData:
OK, that seems very reasonable... I do want common interface for parsers.
class ParsedData
{
public:
class Parser
{
public:
/* necessary common methods */
virtual ~Parser() {}
};

Why should this class be in public section of ParsedData if only methods of
ParsedData will use it? Is it because I won't be able to inherit from it if
I make it private? What if I make it protected, is it possible to inherit
then? I assume it is but I'll try to see what compiler says about it. It
seems that would be closer to that what I want to achieve...
ParsedData() {
// creates the necessary parser (possibly by using
// some kind of factory) and uses the common methods
// to parse
}
};

File formats are recognized by first few lines so I thought using
ParsedData ctor to find out what kind of file it is and use needed parser.
Though, this is irrelevant for now...
class ParserOne : public ParsedData::parser
{
/* all additional member functions */
/* necessary methods */
};

class ParserTwo : public ParsedData::parser
{
/* all additional member functions */
/* necessary methods */
};

Wouldn't this still allow instantiating ParserOne and ParserTwo objects? I
don't want to allow this, user should use only ParsedData class itself, and
class handles file management, data changing and exporting into preferred
file format... Yeah, one more thing. ParserOne and ParserTwo don't have any
data members (at least for now) so what happens when I create object of
that kind (what for example ctor of those classes does?)
 
S

SpOiLeR

You basically have one internal data representation (ParsedData), and
four file formats. You also have four utilities (parsers) that
translate from each of the file formats to the single ParsedData type.

You definitely *do* *not* want to "hide" the parser interfaces from the
user. These should be part of a public API. This way you can test them
independently of the client code which uses the parsers. Also, they can
be re-used.

Although this seems logical, I thought that user of class would give
path/filename to ParsedData class and then class would do everything on its
own. Because of that I wanted to hide parsers from user so he doesn't have
to worry about what file format is he working with. ParsedData would handle
importing data through ctor and exporting data through public interface
function(s) into chosen file format.
My suggestion is to have either a) four parser components for each
format which depend only on the 'ParsedData' type,

Yeah, that's exactly what I want to do, but I want to hide interface of
that parsers from user, so they don't have to worry/learn how to call them
(even though they all share common interface). ParsedData ctor does that
job...
or b) one component,
parseddatautil, which defines a namespace ParsedDataUtil containing
static functions that implement each of the four parsers.

No, this isn't enough, they would still be available in that namespace,
and I want to prevent user from directly using parser utilities. As I said,
ParsedData does that job for them so users don't have to worry what file
format are they working with.
(BTW, you
should pick a name that identifies the data, like TradeDate or
NetworkConfiguration, or whatever, rather than "Parsed" Data.)

Yeah, I know, ParsedData has actually nice name which describes exactly
what it contains, but this is irrelevant for now... Thanks anyway...
Putting these helper functions in an unnamed namespace within the .cpp
file is fine as long as they don't need to access any private member
data. Even then, you may be able to pass these as parameters to the
helper functions.

Yes, that's exactly what would have to be done in this case and does
exactly what I want but I was wondering if this is a good coding
practice...
ParsedData sounds like a value-semantic type (it represents a value
rather than a mechanism), in which case it defines a get/set interface
for each data member, plus a copy constructor, and an assignment
operator. In this case, there is no reason for parser classes to be
friends of ParsedData. They can just use the public interface of
ParsedData.

Definitely, it was just one of the ways I thought about the problem, and
putting parsers into private part of ParsedData interface, makes their code
much readable because they have immediate access to ParsedData data
members. This is obvious. As I said, thing that is not obvious is what to
do with helper methods of parsers which have no need for that access.
Keep asking questions. /david

That's sure to happen :)) Thanks...
 
V

Victor Bazarov

SpOiLeR said:
OK, that seems very reasonable... I do want common interface for parsers.


Why should this class be in public section of ParsedData if only methods
of
ParsedData will use it? Is it because I won't be able to inherit from it
if
I make it private?

I believe so.
What if I make it protected, is it possible to inherit
then?

Only if you derive from ParsedData, you'll be able to access protected
members of ParsedData in the derived classes.
I assume it is but I'll try to see what compiler says about it. It
seems that would be closer to that what I want to achieve...


File formats are recognized by first few lines so I thought using
ParsedData ctor to find out what kind of file it is and use needed parser.
Though, this is irrelevant for now...


Wouldn't this still allow instantiating ParserOne and ParserTwo objects?

Yes, why does it bother you? Shouldn't ParsedData be allowed to do that?
I
don't want to allow this, user should use only ParsedData class itself,
and
class handles file management, data changing and exporting into preferred
file format...

And how is user going to see those parsers? How is he going to ever know
how many there are and how to instantiate them (even though their public
interfaces will allow it)?
Yeah, one more thing. ParserOne and ParserTwo don't have any
data members (at least for now) so what happens when I create object of
that kind (what for example ctor of those classes does?)

I am not sure I understand the question. What relevance does the absence
of data members has on creation of objects of that type?

V
 
S

SpOiLeR

I am not sure I understand the question. What relevance does the absence
of data members has on creation of objects of that type?

Obviously no relevance at all (well it became obvious after a cup of coffee
away from my monitor :))

Anyways, I've been experimenting in the mean time, and I like solution you
proposed... Thanks for your time. I'll be back here when I learn some more
or have some other questions on things learnt so far...
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,768
Messages
2,569,574
Members
45,051
Latest member
CarleyMcCr

Latest Threads

Top