2

Some classes have methods that don't match up with procedural data abstraction. Here is an example of a problem hierarchy, the Render() method doesn't seem to be part of an procedural data abstraction (required for ADT) at all.

My question is should the Render() function be inside the class anyway and why?

#include <SomeGfxLib.h>

class Shape {
public:
    virtual void Render() = 0;
private:
    Color tint;
};

class Circle : public Shape {
public:
    virtual void Render() {
        SomeGfxLib::DrawCircle(); // call complex drawing procedures
    }
};
7
  • 4
    How do you define "valid?" Mar 6, 2021 at 16:43
  • 1
    I feel your question is a bit unclear; it would help if you defined key terms. For example, the term "procedural data abstraction (PDA)" comes from William Cook as a more precise name for OOP. Cook makes a distinction between ADTs and objects of OOP, and calls the abstraction mechanism behind objects the procedural abstraction (in line with the code you've presented), but asserts that ADTs are based on data abstraction (not the case here, in that specific sense). Now, you can find these and similar terms used in somewhat different ways, so expanding on the question would be really helpful. Mar 6, 2021 at 16:44
  • 2
    References: Cook 1990 & Cook 2009 Mar 6, 2021 at 16:44
  • 5
    BTW, I'm not saying that you have to use those terms in the same way these papers do, just that we who are reading your question might not be thinking of the same concepts as you are, so I'm really just asking you to expand on what you mean when you say "doesn't seem to be part of an procedural data abstraction (required for ADT)". Like, in what way? What expectations aren't met in this example, so that you reach that conclusion? Be more explicit about the specific thing that's bugging you. Mar 6, 2021 at 16:56
  • 2
    @FilipMilovanović very interesting papers which seem to explain very well OP’s confusion. Let me know if you’d make an answer with a brief summary and the reference, I’ll upvote. This contribution really deserves not to be lost in some comments :-)
    – Christophe
    Mar 7, 2021 at 10:56

2 Answers 2

5

If your design is to have such a method, the method is “valid”. Now if it is a good idea depends on how you intend to solve the problem with your design.

You can render a simple 2D wire-frame scene by rendering each shape of a collection one after the other. But the problem here is the separation of concerns: now all your shapes are coupled to your graphic library. If you change library, and perhaps even platform, you’ll have a huge work.

A more evolutive way could be to use the bridge pattern: your shape abstraction stays uncorrupted by your graphic environment. It relies on an implementation layer that can evolve independently to the shapes. Each method of the abstraction invokes one or several low level methods of the implementor.

Note that I wrote “more evolutive”. Not “better”. It’s a question of balance: I want evolutivity, it’ll cost me some complexity. There is no free lunch.

Now, back to your question: maybe there’s a deeper conceptual problem. For example you may want the renderer to decide which shape to draw and which part is hidden. In this case, the current rendering design would be insufficient. In this case you may need a Renderer object that interacts with the shapes. Maybe it’s even a combination of both, with a shape abstraction having a shape implementor that acts as a proxy in a colection owned by the Renderer?

There a plenty of ways this can be modeled. We can’t tell what’s best. If you tell more, we can help you find what’s most suitable.

1
  • Thanks for your input, i think the problem is i was considering the class not as a type but as an object Mar 6, 2021 at 13:56
5

There are four reasons to hang a function on an object:

  1. Provide the function access to the private state of that object
  2. Group conceptually similar functions together
  3. Polymorphism, that is, to change the implementation of this function as other functions on that object change their implementation.
  4. Because you’re an Object Oriented zealot who thinks every function should be hanging from an object

If you can’t point at one of the first three then the fourth is pointing at you.

11
  • There are other good reasons. For example, if most or all of the data / information used by the function reside in the object. Or, if adding the function simplifies the API or allows for greater information hiding.
    – user949300
    Mar 6, 2021 at 22:40
  • @user949300 that’s reason 1. It allows such data to be kept private. Mar 6, 2021 at 22:40
  • 1
    @user949300 thanks for the feed back. I simply couldn’t see the other way to read it. Mar 6, 2021 at 22:51
  • 3
    There is also a point 4b: The language-designer was/is a zealot for OO purity and foisted it on all users. Mar 6, 2021 at 23:18
  • 2
    @MartinMaat Calling it BDUF is gentle. Some wont let you use virtual without a good justification. I'm not calling for a micro optimization. I'm just saying it's BDUF until you show me at least TestCircle. You're writing code that might be useful. YAGNI is sometimes wrong. But it's the right conversation to have here. Otherwise everything gets an abstract base class. Sometimes the wrong abstract base class. Mar 7, 2021 at 12:49

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.