0

I am creating a multiple wrappers/layers API in Java that go like this

  1. public class Layer1<T extends Layer1>
  2. public class Layer2<T extends Layer2> extends Layer1<Layer2>
  3. public class Layer3 extends Layer2<Layer3>

with methods like public T sees(){ return (T) this;} within each layer

What is the correct way for the above structure to work as to be able to maintain the original object's, we start the chain with, type throughout the call. Aka the following to be feasible: 3rdLayerObject.1stLayerMethod().2ndLayerMethod(); where the 1stLayer method call returns a 1st layer object(instead of subclass 3rd) and therefore calling a 2nd layer method returns an error.

Why the API is structured as such:

1st layer has only the methods that apply to all situations

2nd layer has client specific methods that either override the 1st wrapper's basic implementations or are entirely new

3rd layer has project specific methods that are mainly new methods used only by this project.

Of course, if you think the above structure is flawed and there is another pattern/structure to use to organize this more effectively I am open to any and all ideas.

  • 1
    Why are you doing this? I think you are missing <T> from your extends 1stTestBase<2ndTestBase>, but this is a horrible class hierachy – Caleth Sep 4 '17 at 14:06
  • @Caleth edited post to add a bit more insight to what I am doing Of course, if you think the above structure is flawed and there is another pattern/structure to use to organize this more effectively I am open to any and all ideas. This is why I posted this in SE stack exchange and not SO to begin with. – Leon Sep 4 '17 at 14:25
  • is Layer a euphemism for Foo, or is that what you're really calling the class? – Robert Harvey Sep 4 '17 at 14:49
  • @RobertHarvey its a euphemism for each abstraction level as explained at the end of the post just so I can make the question as simple as possible. – Leon Sep 4 '17 at 14:53
  • 1
    What strikes me as a litte off about your approach is that you are using the term "layer" but you chained call example (i.e. 3rdLayerObject.1stLayerMethod().2ndLayerMethod();) exposes the layers to the client code, which a layered architecture should try to hide. – Viktor Seifert Sep 5 '17 at 8:45
2

From this line only 3rdLayerObject.1stLayerMethod().2ndLayerMethod() I suspect that you may want to implement something like this:

class Layer1<T extends Layer1<T>> {
    public T layer1Method(){
        return (T)this;
    }
}

class Layer2<T extends Layer2<T>> extends Layer1<T>{
    public T layer2Method(){
        return (T)this;
    }

}

class Layer3<T extends Layer3<T>> extends Layer2<T>{
    public T layer3Method(){
        return (T)this;
    }

    public static final <U extends Layer3<U>> U newLayer3Instance(){
        return (U)new Layer3();
    }

}

So that you can perform this:

Layer3.newLayer3Instance().layer1Method().layer2Method();

I was struggling for long to get such a solution. Unfortunately in java, generics themselves are not enough. You need to add some magic also..

--- EDIT

Layer 4 would be:

class Layer4<T extends Layer4<T>> extends Layer3<T>{
    public T layer4Method(){
        System.out.println("layer4Method");
        return (T)this;
    }

    public static final <U extends Layer4<U>> U newLayer4Instance(){
        return (U)new Layer4();
    }

}

e.t.c...

  • Your getInstance Method is broken. It can be asked to return an arbitrary subclass of Layer3, which it cannot provide - in which case it will fail at runtime. (see this SO question) – Hulk Sep 5 '17 at 12:14
  • @Hulk I've tested the code on java 1.8 and it works. – Marinos An Sep 5 '17 at 12:27
  • 1
    It works until someone writes a subclass class Layer4 extends Layer3<Layer4> {...} and assigns Layer4 l4 = Layer3.getInstance(); which compiles perfectly fine but fails with a ClassCastException. – Hulk Sep 5 '17 at 12:39
  • @Hulk Correct! A solution could be to rename getInstance to getLayer3Instance (or more correct to newLayer3Instance), and make it final. Every layer that wants to provide a newInstance functionality should create a final newLayerXInstance(). I'll add it on my answer. – Marinos An Sep 5 '17 at 13:58
  • adding final to the factory method does not really help here - the method is static anyway, and shadowing is not the problem we are facing. Layer3 would need to be final, and then there is no reason for it to be generic anymore: final static class Layer3 extends Layer2<Layer3>. – Hulk Sep 6 '17 at 14:50
0

It does sound like ordinary inheritance. It also sounds like you think you've uncovered an ontological truth about the world in which this software lives. You have a core set of features, followed by a client specific implementation, followed by many projects at a particular client.

Sounds like a reasonable abstraction in light of your ontological commitment. Sounds like a reasonable way to organize your code.

What happens if you need want to share common code from a number of clients or projects within the same client, or even project related code across clients?

Those classes in your hierarchy won't be your units of code reuse anymore. You'll have to start moving the common functionality into other modules. That's where I would start thinking about the architecture, where the abstraction breaks down.

But maybe you never need to do the above.

  • First of thanks for taking the time to reply, on topic, so far I dont need to go there(project related code across clients). What is the main question and the issue I have is that I cant seem to make it work so a chain call of a top level object to a method inherited in a lower level returns a top level object again but "downgrades" to that level object. ie ProjectObject..CoreMethod().ClientSpecificMethod() wont work because the core method will return a core object that obviously wont have access to any client specific or project specific method. – Leon Sep 5 '17 at 6:47

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.