Classes for Data, InputValidation, Container & Algorithm

This might seem obvious to a lot of people, but I haven't seen anything written about it, so I am posting it to see what everyone thinks. Hopefully it might be useful to someone. It is aimed at the low end of intermediate level say, but I am sure the more expert people might have some comments.

I first started thinking about this because of a comment by helios quite a while back. He was saying that atomic classes should be as lightweight as possible.

The first thing seems to be to separate the data from it's input & validation. Rather than have external functions to do this, collect them into a class. To me, it makes sense not to construct an object until one has valid data to do it with. Also it might be better than having constructors in the Data class throw exceptions for this purpose - of course they could still throw for other reasons like allocation for example.

Placing the input & validation in it's own class allows for preconditions to be tested before anything is constructed. The Input-Validation class would finally instantiate a single object, once it is sure that all the data is OK.

Once we have an object with valid data, we almost certainly want to have a collection of them, so this is where the Container class comes in. For a small program, one might just use a STL Container in main(), but even that could be put in it's own class. A minimum interface would allow the returning of an individual object, so that it's STL member functions & algorithms could be used. More likely, one would provide functions so that the private nature of the member storing the objects would remain intact.

Finally there is the Algorithm class. If for example we have classes that handle geometric entities like points, lines, circles & polygons, then it makes sense to me to put functions that test or calculate with these objects, into a template class.

So rather than trying to define a line intersection test into the line class, make a template function for it, in an algorithm class.

It would be easy to see how all 4 of these classes mentioned so far would be templates.

So what do you all think? Am I barking up the wrong tree, or is there some merit in it? I look forward to any suggestions or comments.
Last edited on
With the lightweight classes idea, just wondering why that is? Maybe I should ask how memory is laid out for a class? Probably different to what I presumed it to be.

For example, if there is a class that has multiple functions and multiple objects of that class type, I would have guessed that the compiler has the code for each function in one place, regardless of how many objects there are. Is that how it works? If so, why does it matter that a class has lots of functions and operators?

If there is a need to factor out stuff from a Data class, I am wondering to what extent that can be done? I could put quite a bit of stuff into the algorithm class, but I am thinking there are some things that should stay in the Data class, like it's operators (unless they interact with another class -> friends) and polymorphic functions like double Area(Shape* pShape) say, because we want Cirlce to call it's own virtual Area function say.

As always I look forward to any comments, and thanks in advance for your time. :+)

Anyone have any comments - good or bad?

Should I troll for comment by asking whether I should have the NERVE to say my proposal could be a Design Pattern?
It is actually a pattern:

1
2
3
4
5
6
7
8
9
class ObscureData;
class Foo
{
  public:
    int bar();
    void baz(int);
  private:
    ObscureData* data;
};

That way you can hide internal implementation in its own class defined in .cpp file, so users of your class couldn't manipulate hidden data even by using:
1
2
3
#define private public
#include <Foo.h>
#undef private 

Also member functions does not add any weight for class. It is internal variables, keeping synch between different parts of class and large amount of data which makes it heavy for concurrent access.


As for point class example you complained elsewhere:

Imagine that one day point class will contain additional fields a and r denoting polar coords of a point.
If x and y have setters (trivial), you can just throw code updating a and r making it non-trivial, but without breaking existing code.
If not you are screwed: you can change access to setters, breaking old code or add update() function which will correct a and r depending on x and y. New code will have to manually call update before accessing a and r, making decision to store them inside a class instead of recomputing all the time useless. And interface would be ugly after that.
Last edited on
After actually reading your thread, I must say that having class
1
2
3
4
5
6
class foo
{
  public:
    int x, y;
    void set(int z);
};
is no different from
1
2
3
4
5
6
7
class foo
{
  public:
    int x, y;
};

void set(foo* this, int z);
Additional methods does not increase class size. They do increase code size, but it is hardly ever matters. Only way when method can increase class size, if that method is first virtual method of the class. In that case constant pointer to virtual table is added to the class.

So moving out methods will not help to make it faster or smaller.

Also, classes should check its invariants itself. It is a staple of encapsulation. You shouldnt have to know which limitation applies to the sides of the triangle: it should tell about incorrect data itself.

Though doing basic input validation and moving out data input is a good idea. It work well with Builder pattern (to decrease amount of constructors and to not create utility classes which only purpose is to hold construction options.) And it works well with GRASP, especially Creator pattern. http://en.wikipedia.org/wiki/GRASP_%28object-oriented_design%29#Creator
Also it helps decouple classes (for example having a constructor which expects istream to read all information is a very bad idea)


I don't understand your point about Container: we already have all sorts of containers in STL.

About Algorithm class: this is not Java. I do not see how coupling these functions in a class will help. I would prefer to do something like:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
namespace geometry
{
class point {...};
class line {...};
std::optional<point> intersection(const line& lhs, const line& rhs);
//...
}

int main()
{
    geometry::point x = geometry::createPoint(std::cin);
    geometry::point y(0, 0);

    geometry::line m = geometry::createLine(std::cin);
    geometry::line n(x, y);

    auto p = geometry::intersection(m, n);
}
Carrying on from here, to answer NwN:
http://www.cplusplus.com/forum/general/112345/#msg614180


See my description of an example below:

With the friend functions, I was trying to find out if it was worth factoring out as much as possible from the Data class. Given MiiNiPaa's answer, it is not worth doing that for member interface functions. I managed to move some of the heavy calcs to the Input Validation class though. The problem with friend functions or classes between the Data class and an Algorithm class is that I would have to keep adding friend declarations to the Data class for each new algorithm function, which I definitely don't want to do - the Data class shouldn't change.

Although I would also say that friends don't necessarily break encapsulation, but they do seem to increase coupling.

Crikey, I hope that people don't get the Data & Container class concepts mixed up - maybe I should refer to it as the Item class?

@MiiNiPaa

Thanks for your comments - appreciated.

When you say Obscure data, is that in reference to the idea of a Container class, or an Algorithm class?

If it is the container class, how is that different to say a std::vector<Class> in main()? Another example may be a Bank class which has a private member that is a vector of Account objects, with say a find function that returns an individual account, which then can used via it's interface.

If it is the Algorithm class, how is that different to the STL algorithms? I mentioned putting a line intersection function into an algorithm class, rather than in the line class.

MiiNiPaa wrote:
Also member functions does not add any weight for class. It is internal variables, keeping synch between different parts of class and large amount of data which makes it heavy for concurrent access.


Ok, good. I will provide an example to demonstrate what I meant specifically.

I was thinking about a circular arc class. There are lots of ways to specify an arc, one of them is 3 points on the arc. Now this takes a reasonable amounts of calcs to come up with a centre point & radius, startangle and endangle, and involves a number of internal variables and private functions. So I was thinking rather than have constructors for each way of specifying an arc, have them as overloaded functions in the CArcInputValidation class. This could possibly be a singleton - whatever we only need 1 object of this type, to be used repeatedly to create CArc objects. The overloaded functions would do all the validation of the input, and all the calcs, and finally call the only constructor in the CArc class, using only data for centrepoint, radius, startangle and endangle. So this saves all the internal variables. The CArc class still has it's interface.

Now the Container class. It has a private member which is a container of CArc objects - std::vector<CArc> say. The class has an interface that does all the classic container functions - retrieve, add & delete items etc.

The Algorithm class would have functions like PointInCircle say, but more likely generalised: bool IsInside(CGeometry Obj1, CGeometry Obj2).

Functions like Move, Rotate, Scale, Copy etc could probably be virtual functions in the Data class.

I hope this example clears up what I was intending.

@MiiNiPaa

With your point class example, I see what you are saying - it is a good example of the advantages of an interface, and I can see how it doesn't break existing client code. It bugs me that the set functions are public though - how to prevent malicious use? I already mentioned virtual functions, what about send / receive functions?

Anyway, the good thing about mentioning ideas, is that it gives you guys a chance to shoot it down, and / or provide advice about a better way - all of which is welcome to me

EDIT: I spent ages writing this, so will now have to digest MiiNiPaa's latest post.
Last edited on
It's 04:00AM at my end, I have to be up in 4.5 hours - doing an all-nighter looks too hard, so will look at this a bit later. Thanks for the input - cheers !

EDIT:

Just saw your last post - my last big post was written before I saw your previous post - so we are playing tag a bit here. Any way later .... ZZzzzz.....ZZzzzz.....ZZzzzz.....
Last edited on
TheIdeasMan wrote:
It bugs me that the set functions are public though - how to prevent malicious use?
const geometry::point origin(0, 0);

TheIdeasMan wrote:
When you say Obscure data, is that in reference to the idea of a Container class, or an Algorithm class?
I was referring to actual practice of providing an interface but hiding all implementation details so you couldn't use them even if you really want. It was an example of decoupling data and interface.

TheIdeasMan wrote:
...
The overloaded functions would do all the validation of the input, and all the calcs, and finally call the only constructor in the CArc class, using only data for centrepoint, radius, startangle and endangle.
I have already answered that it is a good idea. Check Builder, Factory Method patterns and a link to GRASP wiki article.

TheIdeasMan wrote:
Now the Container class. It has a private member which is a container of CArc objects - std::vector<CArc> .
Like Facade pattern? And why would you need it if you can just use std::vector directly? Remember, that you will need different containers depending on situation, so you will end with ContainerVector, ContainerSet, etc. classes. If you want neat naming you can just use typedefs.

Also I see that you want yor algorithm class to be singleton. This will still have some costs. To circumvent this you can use static member function to use them without creating instance:
1
2
3
4
5
6
class alg
{
    static int check(line);
};
//usage:
int result = alg::check(someline);
And wer are returning to my previous post: why not namespaces?
1
2
3
4
5
6
namespace alg
{
    int check(line);
}
//usage:
int result = alg::check(someline);
Last edited on
> I should have the NERVE to say my proposal could be a Design Pattern?

You can definitely say that your design involves a few design patterns. Which are used together (as design patterns usually are) in a specific context, which is of course your own very special context.

The strategy pattern, often implemented implemented in C++ via policy parameterization. For instance, the input validation policy http://en.wikipedia.org/wiki/Policy-based_design

The mediator pattern. For instance the geometric object intersection mediator.
http://en.wikipedia.org/wiki/Mediator_pattern

The Facade pattern. For instance the arc creation facade.
http://en.wikipedia.org/wiki/Facade_pattern

Perhaps the Abstract Factory pattern or the Exemplar pattern is involved in object creation, and possibly the objects use shared state (Flyweight pattern). But I'm guessing, I haven't at all understood that part of the proposed design.
@MiiNiPaa

I was 1 post behind in our exchange last night, so some of the my reply didn't match what you had in later post.

const geometry::point origin(0, 0);


Ok, but what about this:

1
2
const geometry::point MyPoint(10.0, 20.0);
MyPoint.Move(5.0,7.0); // error MyPoint is const 


I had thoughts of a Geometry base class with virtual functions for editing - Move, Rotate, Scale, Stretch etc. That way, they can have direct access to private members.

MiiNiPaa wrote:
I don't understand your point about Container: we already have all sorts of containers in STL.
MiiNiPaa wrote:
Like Facade pattern? And why would you need it if you can just use std::vector directly? Remember, that you will need different containers depending on situation, so you will end with ContainerVector, ContainerSet, etc. classes. If you want neat naming you can just use typedefs.


I am not sure it needs to be as complicated as that. With the Bank Account example, sure we can use the functionality of the STL container we put them in, as well we might have all kinds functions that work on all the accounts (and their transactions), like ApplyFees, CalcInterest etc. So where to put this code? In main()? As external functions in another .cpp file? Why not collect them all into their own class? - was all I was thinking.

With different containers for different situations (with the same set of objects), I was hoping to avoid that. If it is necessary, then it would indeed be a complication. Would probably need some serious thought on Design Patterns. See below for some comments on a CAD system.

Also, classes should check its invariants itself. It is a staple of encapsulation. You shouldnt have to know which limitation applies to the sides of the triangle: it should tell about incorrect data itself.


Ok, so basic validation is good - my intention was to avoid creating invalid objects to start with. So I take it you mean that mutator functions should keep the object in a valid state - that was always my intention.

About Algorithm class: this is not Java. I do not see how coupling these functions in a class will help. I would prefer to do something like:


Funny thing - I know very little about Java ! :+) But my idea was to move these functions out of the Data class - which is what your code does. And I was thinking that is what the STL does with it's algorithms. The namespace idea achieves that, so that's fine by me.

Also I see that you want yor algorithm class to be singleton.


I was saying the InputValidation class, but I get your point about static functions though. And it looks like a good idea to do this for the algorithms too- as you say. I was just saying that I only need 1 instance of this class to be used repeatedly to create the objects. I didn't want anyone thinking I was going to have a container full of them or anything.

Some other thoughts I had:

The Circular Arc is just 1 example of many types of objects that are in a CAD system. Even with a small set of object types, it could be easy for it to turn into a monolithic beast! For example, one often draws new objects by selecting vertexes or other snap points on existing drawing entities. I might want to draw an arc by the 3 point method using the a vertex of that hexagon, the intersection of those 2 lines, and the centre of this circle. To me, the use of various get functions that belong to each type of entity, through a Mediator Pattern seems the easiest thing to do.

Although things get trickier when deal with the more general situation of all the entity types, with all their creation methods, and all their editing methods. I will have to ruminate more on how the Design Patterns would work, so I can reply to JLBorges.

Thanks to all for your replies - cheers.

TheIdeasMan wrote:
Ok, but what about this:
You just have another interface. My p.setX(x) mutator is equivalent to, say p.move(x, p.getCoords.second) in your code. No differences. Looks I was mistaken in what do you mean by "malicious". Any way you can misuse setX(), you can misuse move().

Containers
You can have bank class which stores accounts in some kind of STL container and provides interface and methods to work with them. This is often used example when describing classes and encapsulation. Nothing new.
Topic archived. No new replies allowed.