Re: Properties Shared Amongst Objects




"H. S. Lahman"

<snip>

However, for the complexity of your example, I suspect that might also be
overkill. The interpolation algorithm can be parameterized so the same
algorithm is used for all comonents. IOW, one wouldn't need to subclass
the strategy; one would just need attributes in [Group], such as the
settling time to reach a new value, that characterize how the
interpolation should work for a particular group. If so, that algorithm
can be in Group.interpolate().

Thanks for your response. It's insightful as always.

When I post to comp.object, it's sometimes difficult to strike a balance
between posting too little information and posting too much. So I thought
I'd follow up with more details.

(BTW, I used the word property in my previous post. I'm going to switch to
the word parameter to mean the same thing.)

The applications that I'm writing are dll's (dynamic linked libraries) that
are run inside of a host. The host can query my application for certain
information. For example, it can ask for the number of parameters my
application uses. It can also ask for a parameter's value, name, label, and
a human readable string representing its current value. Also, it can set a
parameter value. Parameter values from the host's perspective are always in
the range of [0, 1].

So the view of my application from the host's perspective is very flat, a
list of parameters and their values (there are other ways that the host and
my application interact, but for the purposes of this post, I'll skip those
details).

I might have something like this in my code:

enum ParameterId
{
AmplitudeLevelId,
FrequencyId
};

//
// Called by the host:
//

float GetParameterValue(int parameterId)
{
float value;

switch(parameterId...

return value;
}

void SetParameterValue(int parameterId, float value)
{
// ...
}

void GetParameterName(int parameterId, char *name)
{
// ...
}

Whereas this flat view is useful for the host, it's not so useful for my
application. For example, a frequency parameter value may need to be mapped
to a more useful range than the [0, 1] range the host uses, say, [20,
20000]. Also, an amplitude parameter value may need to map parameter values
to an exponential curve. In addition, it's useful for my application to
create an object oriented architecture in order to manage behavior. After
some consideration, I might group some of the parameters into classes. Using
the above example, I could have this:

class Amplifier
{
public:
float GetAmplitudeLevel() const;
void SetAmplitudeLevel(float amplitudeLevel);
void GetAmplitudeName(char *name) const;
void GetAmplitudeLabel(char *label) const;

// ...
};

class Oscillator
{
public:
float GetFrequency() const;
void SetFrequency(float frequency);
void GetFrequencyName(char *name) const;
void GetFrequencyLabel(char *label) const;

// ...
};

It then becomes a matter of mapping parameter changes to the component
objects that represent those parameters.

What I noticed after factoring parameters into several classes is that I was
duplicating code for converting parameter values to/from the host. For
example, I noticed that some parameters behave like an on/off switch,
mapping parameter values less than 0.5 as "Off" and greater than or equal to
0.5 to "On." Also, some parameters represented a selection, e.g. Red, Green,
Yellow, etc. In all, there are three or four parameter types I discovered.

So I thought it would be advantageous to create a set of parameter classes.
The base parameter class would provide functionality common to all parameter
classes. Derived parameter classes would specialize parameter values, e.g. a
SwitchParameter to represent an on/off parameter.

My amplifier class could then look like this:

class Amplifier
{
private:
ExponentialParameter amplitudeLevel;

public:
Amplifier() :
amplitudeLevel("Amplitude", "dB");
{
}

float GetAmplitudeLevel() const
{
return amplitudeLevel.GetValue();
}

void SetAmplitudeLevel(float level) const
{
amplitudeLevel.SetValue(level);
}

// ...
};

So far, so good. But as I mentioned in my original post, I might have
several components that belong to a group. The components in the group all
sharing the same parameter/property values. So why not create the parameter
objects seperately and pass them to each component in the group?

class Amplifier
{
private:
ExponentialParameter &amplitudeLevel;

public:
Amplifier(ExponentialParameter &amplitudeLevel) :
amplitudeLevel(amplitudeLevel)
{
}

// ...
};

ExponentialParameter amplitudeLevel("Amplitude", "dB");

Amplifier amplifier1(amplitudeLevel);
Amplifier amplifier2(amplitudeLevel);
// ...

The parameter objects for the entire application can be added to a
collection. This makes it relatively trivial to map parameter changes
to/from the host:

float GetParameterValue(int parameterId)
{
return parameters[parameterId].GetValue();
}

This seems to work pretty well in practise, though there's a few rough edges
I need to work out. I'm posting this more as a sanity check, however. Just
curious if this falls into any recognized pattern.


.



Relevant Pages