2

Motivation: (Skip to "The Problem" if you don't need motivation for it)

As a project for myself, I'm writing an expression parser for certain kinds of mathematical expressions, and I'm using the interpreter pattern (as it often is used) for my Expression classes.

At the same time, I'm also using the template method pattern for certain operations I wanna do on my Expressions. My use of the template method pattern is where the template method is "public", but the primitive operations called by the template method should not be "public" to the user. (This is how I learnt it, and this feels like it makes the most sense for my program.)

The specific example I was dealing with was trying to simplify an expression; there are several different simplification functions (let us call them simplify1, simplify2, and so on) I used, and each are called inside the Expression class (for example, one of my simplification functions evaluates all constant expressions, e.g. 1+2^(2*3) simplifies to 65, another simplification function simplifies repeated operations, eg. x+(3+x^2) simplifies to x+3+x^2). The way this works in each of the Expression subclasses which are non-terminal is that there are recursive calls to the contained expressions, until a terminal "Constant" or "Variable" is reached.

Now, the problem is that these different simplification functions should be hidden from the user; the interface should only allow a call to the template method "simplify", which calls all the different simplification functions as needed. Initially, I thought that making those simplify functions "protected" would solve the problem. That is, in my child classes, I would have "simplify1", "simplify2" and so on overridden, and then in the parent expression class, "simplify" would call "simplify1", then "simplify2", and so on, and "simplify" itself would be public. However, the problem is that in non-terminal classes (an expression that itself contains expressions), having a protected modifier on simplify1, simplify2, and so on, does not allow it to call simplify1, simplify2, etc. on the contained expressions.

The Problem:

Abstracting away the motivation ("Expression" becomes "Parent", the different derived expression classes are the "Child" classes ("ChildC" specifically is a non-terminal expression), "simplify" becomes "publicFoo", and "simplify1" and "simplify2" become "foo1" and "foo2" respectively), I want code that behaves like this:

class Parent { //abstract expression
protected:
    virtual void foo1() = 0; //primitive operation, don't wanna give access to public
    virtual void foo2() = 0; //primitive operation, don't wanna give access to public

public:
    void publicFoo(){ //template method
        this -> foo1();
        this -> foo2();
        //maybe does other things too
    }; // this is what the user will call

};

class ChildA: public Parent { //terminal expression
protected:
    void foo1() override; //whatever implementation
    void foo2() override; //whatever implementation

};

class ChildB: public Parent{ //terminal expression 
protected:
    void foo1() override; //whatever implementation
    void foo2() override; //whatever implementation

};

class ChildC: public Parent { //non terminal expression
   std::vector<Parent*> parents;
protected:
    void foo1() override {
        for ( auto p: parents){
            p->foo1(); //calls correct foo1 depending on what p truly is (this does not compile)
        }
    }
    void foo2() override {
        for ( auto p: parents){
            p->foo2(); //calls correct foo2 depending on what p truly is (this does not compile)
        }
    }
};

So, the problem here is that "protected" actually doesn't allow calling foo1 or foo2 on arbitrary Parent type objects, only on ChildC objects, and the compiler gives me errors saying "'foo1' is a protected member of 'Parent'" and "'foo2' is a protected member of 'Parent'". It feels like what I want is a modifier that's something like "semi-protected", which allows access for a derived class to call semi-protected functions of any kind of parent object.

Temporary Solution:

My current solution to this is to simply make the ChildC (in the example above) a friend class to Parent, and then make foo1 and foo2 private (because ChildC, as a friend, can access those anyway). However, in my time using C++, I've learnt that friend classes are usually discouraged and are considered bad style (or something of the sort). And in general, the solution doesn't feel as nice as it could be, because I don't need ChildC to have that much access to Parent's members.

Question:

Thus, my question is, is there a nicer way to combine these patterns while ensuring that the primitive operations with the template method pattern remain hidden to the user?

  • I think you're going about this the wrong way. Instead of trying to assemble a program by stitching together software patterns (a demonstrably unworkable approach), why don't you simply create the abstraction you actually need to solve the problem at hand? See also Patterns are Not Building Blocks and The KISS Principle. – Robert Harvey Jan 9 '18 at 23:29
  • 1
    @Robert_Harvey Ahh, the way I phrased the question does make it sound like I'm stitching together patterns, but actually, I encountered the problem more organically than I let on. I started with only an expression parser; the interpreter pattern was the most obvious way to do it. Then, I wanted to add a simplify function, but it became complicated, so i broke it down. I didn't know i had used the template method pattern (I later learnt that that is what it was called). Then, I realized the different steps in my simplification process shouldn't be public, and thus the problem occurred. – Umer Amjad Jan 9 '18 at 23:38
  • 2
    At first glance, it looks to me like you're trying to do what's called double dispatch (determine which function gets called based on actual type of both objects). – Filip Milovanović Jan 9 '18 at 23:50
  • @Filip If I'm understanding correctly, I don't think I'm using a double dispatch. Both foo1 and foo2 are "single" dispatches (not sure if that's a term): the correct foo1 is called in the recursive call for foo1, and the correct foo2 is called in the recursive call for foo2, depending only on the type of p. I just realized in my code example, I wrote "calls correct foo", which makes it sound like it chooses between foo1 or foo2. This is not what I meant (I'll have to edit that). I don't choose between foo1 or foo2, I always wanna call them both. – Umer Amjad Jan 10 '18 at 0:28
  • Maybe use looser access control but only expose a Facade with the public members you want. Or even just don't worry about it. – Derek Elkins Jan 10 '18 at 18:41

Your Answer

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

Browse other questions tagged or ask your own question.