lundi 2 octobre 2023

Which Java design pattern fits better for shared configurations?

I have two "projects". One in Java, the other in Groovy.

The Groovy project: It's actually several classes in a static context. There are configurations and a static exec() function in each procedure, with or without arguments. I must avoid adding parameters as much as possible (so I must avoid passing the configuration as a parameter). In this groovy project, other developers will be able to create their Configuration class and redefine the values of a Configuration superclass, defined in the Java project. They can also create new procedures.

A groovy configuration:

package procedureUtils.config

class Conf1 extends ConfJava {
    Conf1() {
        setMode("1");
    }
}

A groovy procedure:

//procedure1.groovy
package procedureUtils.test

import groovy.transform.Field
import procedureUtils.config.Conf1
import procedureUtils.config.ConfJava

@Field static ConfJava config = new Conf1()

exec()

static exec() {
    println "Procedure1 " + config.getMode()
    Procedure2.exec()
}

The Java project: This project cannot be modified by other developers. It contains a Configuration class (variable values can be redefined in groovy custom configurations). There is also a Default Configuration that developers can use in the groovy project if they don't need to redefine variable values.

The ConfJava:

package procedureUtils.config;

public class ConfJava {
  private static String mode = "abs";

  public ConfJava() {
    // empty
  }

  public static String getMode() {
    return mode;
  }

  public static void setMode(String newMode) {
    mode = newMode;
  }
}

The default java conf:

package procedureUtils.config;

public class ConfDef extends ConfJava {
  public ConfDef() {
    setMode("def");
  }
}

Purpose: These configurations are used in the groovy project, in the "procedures" files. Each script can call the exec function of another script. What's important is that I'd like the parent script to propagate its configuration to its children.

So far, I have:

  • ConfJava.java, which serves as the parent class
  • ConfDef.java, which is the default configuration
  • ConfX.groovy, where X can be anything. The mode value will be the same as X for the example.
  • ProcedureX.groovy, which are the classes using the configurations

Ideally, ConfJava shouldn't be instantiable, but that's the only way I've managed to get it to work.

Currently, propagation only works if the procedure's static "config" field is in the form "new ConfJava()" with a parent procedure that has :

  • either put "new Conf1()" in the static field
  • redefined "config = new Conf1()" in the contents of its exec function.

My problem is that there may be end procedures that also define the static field. I'd like this definition to be made only if the script is called as a parent script.

Example: Currently, here's the perfect case where we don't redefine anything (the configuration propagates well because otherwise, it should print "Procedure3 abs") enter image description here

But now, if I change the instantiation in the groovy procedure2 with ConfDef(), it will print "Procedure2 def" instead of "1" (because procedure2 is called as a child, so I want it to use the parent configuration). enter image description here

In short, if a script is called as the parent script, it will use correctly and normally the configuration set in the @Field declaration or in the exec function code. But, if a script is called as a child script, I want to use the parent configuration except if the procedure redefine the configuration in the exec function code, as in the Procedure2 example.

Of course, each script can be called as a Parent or a Child.

So first, I don't really know if it's possible? Second, if it is, I would like to know which design pattern will fit this implementation?

Aucun commentaire:

Enregistrer un commentaire