1

I'm coming from C++ and I'm trying to inherit the Generic parameter type in Java. Basically, I'm trying to emulate the below C++ pattern:

In C++, I can do:

#include <iostream>

class Node
{
        Node* next;
};


class BaseVisitor
{
    public:
        BaseVisitor(Node* ptr)
        {
            std::cout<<ptr<<"\n\n";
            delete ptr;
        }
        ~BaseVisitor() {};

    protected:
        virtual Node* Generate() = 0;
};


class DynamicVisitor : public BaseVisitor
{
    public:
        DynamicVisitor(Node* ptr) : BaseVisitor(ptr) {}

    protected:
        virtual Node* Generate()
        {
            std::cout<<"Dynamic Visitor\n";
            return new Node();
        }
};

class StaticVisitor : public BaseVisitor
{
    public:
        StaticVisitor(Node* ptr) : BaseVisitor(ptr) {}

    protected:
        virtual Node* Generate()
        {
            std::cout<<"Static Visitor\n";
            return NULL;
        }
};



template<typename T>
class TestVisitor : public T  //THIS is where the magic happens..
{
    public:
        TestVisitor() : T(this->Generate()) {} //allows me to call "Generate".
};

int main()
{
    TestVisitor<DynamicVisitor> foo = TestVisitor<DynamicVisitor>();
    TestVisitor<StaticVisitor> bar = TestVisitor<StaticVisitor>();
}

Output:

Dynamic Visitor
0x605ed0

Static Visitor
NULL

How can I do the same thing in Java? I tried:

public class Node {
    Node next;
}

public abstract class BaseVisitor {
    public BaseVisitor(Node n) {System.out.println(n);}

    protected abstract Node generate();
}

public class DynamicVisitor extends BaseVisitor {
    public DynamicVisitor(Node n) {
        super(n);
    }

    @Override
    protected Node generate() {
        return new Node();
    }
}

public class StaticVisitor extends BaseVisitor {

    public StaticVisitor(Node n) {
        super(n);
    }

    @Override
    protected Node generate() {
        return null;
    }
}

public class TestVisitor<T extends BaseVisitor> extends T { //error.. Cannot extend "T".. No magic happens..
    public TestVisitor() {
        super(this.generate()); //cannot call generate()..
    }
}
  1. What is this pattern called? I call it "Base Factory" pattern but I'm not sure the real name for it so I wasn't sure what to search for..

  2. How can I do the same thing as in C++, in Java? Is there "any way" to do the same pattern in Java?

1
  • That's where C++ zings while java zangs. In C++ templates are basically fancy preprocessor macros, that lead to different runtime objects being generated. In java, there is only one version of a templatized class at runtime (with its type parameter erased). That forbids you from doing things like the above. You can however come up with solutions using anonymous classes or java 8 lambdas. Commented Jan 15, 2015 at 23:39

1 Answer 1

1

Nope, can't do this in java, sorry. The closest is, probably, a "delegate pattern":

public interface NodeGenerator {  Node generate(); }
public class StaticGenerator implements NodeGenerator { 
    public Node generate() { return null; }
}
public class DynamicGenerator implements NodeGenerator {
    public Node generate() { return new Node(); }
}

public class TestVisitor extends BaseVisitor {
     public TestVisitor(NodeGenerator g) { super(g.generate()); }
}

In java 8, you can make this look nicer (but possibly less efficient), without the extra interfaces and classes:

public class TestVisitor extends BaseVisitor {
    public TestVisitor(Supplier<Node> g) { super(g.get()); }
}

// ... and then you can do things like

TestVisitor staticVisitor = new TestVisitor(() -> null);
TestVisitor dynamicVisitor = new TestVisitor(() -> new Node());
Sign up to request clarification or add additional context in comments.

8 Comments

Why do you suggest it's possibly less efficient?
Well, I said "possibly", because I am not sure about how exactly this is implemented. What I have in mind is something like this: NodeGenerator ng = new StaticNodeGenerator(); for(int i = 0; i < 10000; i++) { new TestVisitor(ng); } vs. for(int i = 0; i < 10000; i++) { new TestVisitor(() -> null); }. It seems to me, that the latter approach is going to allocate 10000 more objects (that can be avoided), and, possibly, generate 10000 extra anonymous classes (that would be unavoidable).
You could replace the first example with anonymous classes and obtain code that's almost as concise as the java 8 version!
@GiovanniBotta ~50 extra characters (3 lines) per call ... :-/
The lambda version doesn't capture anything, so it doesn't need to allocate extra objects. Those supplier calls will just be executed as method invocations by the JVM.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.