ImpossibleCode
ImpossibleCode

Reputation: 11

Structuring java classes to avoid instanceOf

I am trying to create an application in java that loads and configures a range of different GLSL shaders. Currently I've got something like the below, but will end up probably with lots more (30+) more similar classes - each loads an individual shader.

Ideally, I'd like to be able to put the shader classes in a list, and link them up to a GUI so that shader parameters can be retrieved and updated. Apart from same common logic (loading the GLSL file and returning a PShader), the variables (and getters/setters) may be quite different for each class (for example, some GLSL shaders I want to use have no variables, while others may have one or multiple variables - float, boolean, int etc).

I could have some kind of base class, and extend the class to handle different variables, but that still probably leads me at some point having to manage some kind of type checking / using a bunch of instanceOf statements. I'm struggling to see how polymorphism could be readily applied here. I've looked into java reflection, but that didn't get me too far, and have been looking at different design patterns.

Note - this isn't homework. It's just a personal project. So, I'm not concerned about having something that has to be maintained by others, but it has piqued my interest in different design patterns, and I'm wondering if there is a better way to structure this.

public class ChromaColor {

    private Shader shader;
    private float smoothing;

    public Chroma(){
        shader = loadShader("chroma.glsl");
        setSmoothing(0.1F);
    }

    public Chroma setSmoothing(float f) {
        if(shader != null) shader.set("smoothing", f);
        this.smoothing = f;
        return this;
    }

    public float getSmoothing() {
        return smoothing;
    }

    public Shader shader() {
        return shader;
    }

}

Upvotes: 1

Views: 68

Answers (2)

tquadrat
tquadrat

Reputation: 4034

What about using an instance of java.util.Properties as the only parameter for the configuration of a Shader? Or another kind of java.util.Map?

When the shaders all have a simple set of parameters in common (some all of them, some none, others a selection), you can create some type of DSL for the configuration, that checks each parameter value, and each shader type defines in a list which arguments are valid for it.

This would allow you to re-use as much as possible of your code. It would allow also to have getters and setters. Have a look to the classes in java.time for an example how this could look …

It could look like this:

public interface IChromaColors
{
  Set<Parameter> getParameters();

  void configure( Map<Parameter,Object> values );

  Object get( Parameter parameter );

  void set( Parameter parameter, Object value );
}

Parameter may look like this:

public interface Parameter<T>
{
  String getName();

  Class<T> getType();

  boolean validate( T value );
}

Now your class may look like this:

public class ChromaColor implements IChromaColor
{
    private Map<Parameter,Object> m_Values;
    private Set<Parameter> m_ValidValues;
    private Shader shader;

    public Chroma( Map<Parameter,Object> values )
    {
        shader = loadShader("chroma.glsl");
        m_ValidValues = Set.of( SmoothingParameter );

        m_Values = values;
        if( !m_Values.contains( SmootingParameter ) ) 
        {
           m_Values.put( SmoothingParameter, Float.valueOf( 0.1F ) );
        }
        configure( m_Values );
    }

    public Chroma set( Parameter parameter, Object value
    {
        if( m_ValidValues.contains( parameter )
        {
           …
        }
        return this;
    }

    public Object get( Parameter parameter )
   {
        return m_Values.get( parameter );
    }

    public Shader shader() {
        return shader;
    }

}

This is just raw, very raw draft of my idea! So I omitted the problems with the generics for Parameter and the interfaces can be optimised (significantly!), but I hope you get a faint hint on what I mean.

Upvotes: 0

davidxxx
davidxxx

Reputation: 131326

Apart from same common logic (loading the GLSL file and returning a PShader), the variables (and getters/setters) may be quite different for each class

....

I'm struggling to see how polymorphism could be readily applied here. I've looked into java reflection, but that didn't get me too far, and have been looking at different design patterns.

You don't have a lot of ways since you cannot process instances of the different classes (getting and setting properties) in an uniform way.

Either you define a rendering/processing class by class to handle.
Advantage: checks at compile time.
Drawback : much repetitive code to write.

Or you use reflection to retrieve field to get/set in the GUI.
Advantage: much less code to write.
Drawback : no check at compile time.
Note 1) using reflections to retrieve all getters/setters could retrieve private fields that you don't want to expose to the GUI.
If that is the case, annotate fields to include or to exclude may be a way to address that.
Note 2) the no-check at compile time drawback can be mitigated if you write unit tests (probably parameterized tests) that check that properties of instances of the different classes to handle may well be read/write by the GUI.

Upvotes: 1

Related Questions