anony
anony

Reputation: 314

Best design pattern for a scenario

We have a class called Variable which represents a singlevalue or compound value. For example, it can hold an integer,or a boolean,or a String etc... (single valued) or some compound value which can be list of Strings, integers or other Variables.

  1. We serialize these objects and in the stream all these values are represented as strings. Whenever we serialize or deserialize there is a type conversion happening.

  2. There are also some optional features or ways you can fill values in these variables. For example you can define a Variable to be populated from a webpage - For a given Variable we query a cache to understand if it should be populated from a webpage. Whenever someone does getValue() on the Variable we populate the value.

  3. We also want to track changes of some variables. For example, I can choose to record or do some action whenever the value of a variable is read or changed.

As you can see that this is a hierarchical structure because variable can contain other variables. We wanted to find the best way to solve this.

Currently we have only one class called Variable which has so many if/else conditions and the code is very complex. For example, getValue() code does the following:

if(query the cache to see if it needs population from webpage) do something else(---) do something else(if read should be recorded-find from cache) do something etc...

Is there any pattern to design my classes in such a way that all my population from webpage logic can go in to one class, tracking logic in some other class, type conversion logic in some other class etc... to make it more readable.

Upvotes: 2

Views: 2099

Answers (2)

Anders Johansen
Anders Johansen

Reputation: 10475

Chain of Responsibility Each chained element in the Composite gets to do it's bit, but you have to spend some time configuring the runtime structure just so.

Possibly just a Composite or Observer for the getValue() scenario (but sounds more like Composite to me).

EDIT:

One could argue that the implementation below is in fact a case of "Chain of Responsibility", as a composite variable will delegate the responsibility of setting values to its children.

END EDIT

Here's a simple example using Observer and Composite. NOT TESTED just to give you the general feel for the solution...

I have not implemented stuff like serializing/deserializing.

In this solution you have compound values and atomic values, and you can add some observer to be executed before value is set.

package dk.asj.variables;

public abstract class VariableBase {

    public interface Observer {
        void onSet(final Value val, final VariableBase var);
    }

    private Observer obs = null;

    public void setObserver(final Observer obs) {
        this.obs = obs;
    }

    public void setValue(final Value val) {
        if (obs != null) {
            obs.onSet(val, this);
        }
        internalSetValue(val);
    }

    protected abstract void internalSetValue(final Value val);

    public abstract Value getValue();

}

package dk.asj.variables;

import java.util.List;

public interface Value {

    int getIntValue();

    String getStringValue();

    List<Value> getCompositeValue();

}

package dk.asj.variables;

public class SimpleVariable extends VariableBase {

    private Value val = null;

    @Override
    protected void internalSetValue(final Value val) {
        this.val = val;
    }

    @Override
    public Value getValue() {
        return val;
    }


}

package dk.asj.variables;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

public class CompoundVariable extends VariableBase {

    final List<VariableBase> children = new LinkedList<VariableBase>();

    public void addChild(final VariableBase c) {
        children.add(c);
    }

    @Override
    protected void internalSetValue(final Value val) {
        for (int i = 0; i < val.getCompositeValue().size(); ++i) {
            children.get(i).setValue(val.getCompositeValue().get(i));
        }
    }

    @Override
    public Value getValue() {
        final List<Value> res = new ArrayList<Value>(children.size());
        for (final VariableBase var : children) {
            res.add(var.getValue());
        }
        return new Value() {

            @Override
            public int getIntValue() {
                throw new RuntimeException("This is a composite value");
            }

            @Override
            public String getStringValue() {
                throw new RuntimeException("This is a composite value");
            }

            @Override
            public List<Value> getCompositeValue() {
                return res;
            }

        };
    }


}

Upvotes: 2

Andrey Chaschev
Andrey Chaschev

Reputation: 16526

I'm not sure if this answers your question, however, this could lead to some new ideas, here is what I came up with in a similar situation:

  • I named these DynamicVariables. A dynamic variable may have a default value or be evaluated by a lamda (Java 8)/anonymous inner class (pre-Java 8).
  • Each variable has an evaluation context and can be evaluated only in a context - i.e. Session context or a Global context. Contexts fallback to each other and create an hierarchy, i.e. Session context falls back to a Global context. So the default variable constant or lambda value can be shadowed by a lambda or a constant defined in a context. In instance, session-scoped variables shadow out global vars when are accessed inside a session.

And this appeared to be quite a flexible approach - I even implemented a trivial dependency injection by introducing InjectionContext which is a thread-safe context holding an object being wired.

You might want to have a look at an example of how this is used in a deployment tool I'm currently developing. Configuration management and shared application logic there is built upon these variables. Code is under bear.context package, but it's rather raw at the moment.

Upvotes: 0

Related Questions