2

Sometimes we run into a problem where a class doesn't need to use its own properties. See approach A:

struct Ball {
    double mass = 1;
    double x = 0;
    double y = 0;
};

struct World {
    std::vector<Ball*> balls;
    void run_physics() {
        // here we run the physics
        // we can access every ball and their x, y properties
    }
};

In order to avoid this, we can use approach B:

struct World;

struct Ball {
    World* world = NULL;
    double mass = 1;
    double x = 0;
    double y = 0;
    void run_physics() {
        if (this->world != NULL) {
            // here we run the physics again
            // we can access every other ball properties through this->world->balls vector.
        }
    }
};

struct World {
    std::vector<Ball*> balls;
};

But approach B is a tight-coupling structure, which means that both Ball and World know about each other, which is not good.

So, which is better approach?

  • A: Loose-coupling, but some classes will not use their own properties, or
  • B: Classes will use their properties, but tight-coupling structure ?

When to use each one?

Liakos
  • 512
  • 5
  • 10
  • 1
    i dont understand why you want to avoid A, in the first place. What problem are you trying to solve? – 463035818_is_not_an_ai Feb 28 '18 at 13:09
  • Not all objects are designed to do something with their data. Just consider a MVC Pattern. The model can consist of several classes that encapsulate (and structure) data. Your Balls structure is a good example for such a model class. – rbf Feb 28 '18 at 13:10
  • Or approach C: `Ball` (properties like size, colour, or mass that are inherent to "ball-ness"), `BallPhysics` (properties like location or velocity that depend on the nature of the world), and `World`. – molbdnilo Feb 28 '18 at 13:23
  • @molbdnilo: With this approach, which class should know of the other? – Liakos Feb 28 '18 at 14:09

1 Answers1

3

A is better in that is more extensible.

Balls might take on other properties not relevant to the current calculation, such as members for calculating the moment of inertia (if a hollow sphere for example).

So yes, it is acceptable for a class to have its properties used only by the outside environment, since that might not be the case for ever.

That said, if x and y tell you something about the locations of the ball, then those are more to do with a class telling you about the collection of installed ball instances, rather than being part of the ball itself.

Bathsheba
  • 231,907
  • 34
  • 361
  • 483
  • The problem with this is the bad structure logic, since "x" and "y" don't belong to the Ball as a "mass" or a "color" property would. They show the coordinates RELATIVE to World. It is like they do some "tight-coupling" themselves. If the Ball has "x" and "y" properties (relative to World), why not to have a World property too. Seems like you cannot avoid tight-coupling in some cases. – Liakos Feb 28 '18 at 13:16
  • @Liakos: Very true, if `x` and `y` are to do with their location then they should indeed be outside the ball class. – Bathsheba Feb 28 '18 at 13:18
  • But where to store "x" and "y"? If, in World, you put some vectors like balls_x[] and balls_y[] (below balls[]), then it doesn't seem like OOP at all. In addition, inside run_physics(), which will contain lots of loops, you will have to select "x" and "y" by vector indexes, which seems very weird.. – Liakos Feb 28 '18 at 13:22
  • 1
    @Liakos In that case you still want to have a loose coupling ... but as already suggested outside of Ball. Something like: World has a container that holds Balls and their Location, so that a Ball does not know it's location or it's world and the Location does not know that a Ball or a World exists – rbf Feb 28 '18 at 13:22
  • @Liakos Maybe changing the name "Ball" would make things clearer. In your example, it is a 2D coordinate. These 2D coordinates take the signification of a ball (in your example) only inside the `run_physics` method. I believe `std::vector balls` represents well the whole design. – Oliv Feb 28 '18 at 14:04
  • @Oliv: Just added a `mass` property to make my example clearer. – Liakos Feb 28 '18 at 14:19
  • @Liakos, so `lagrangian_point` may be appropriate. What I mean is that the name should reflect the design. I would call it "ball", if there were a method to translate the coordinate, another to compute an elastic colision (for example) with another ball, and all methods that could make it qualified as a ball inside your program. In this case, the coordinate may be hidden properties. Names are design decisions, when names do not reflect design, we doubt about the design, this is what is happeing here. – Oliv Feb 28 '18 at 18:15