March 15, 2007

From Encapsulated Values to Semi-Constants

Decisions to semi-constants
My previous post is about encapsulated decisions. In trivial case, they are just encapsulated values - constants hidden behind the function interface. You can make a step further and make them loadable from some storage. I call such parameters semi-constants, because their values are predefined, but the parameters themselves are not const in the C++ sense.

Listing 1. Example of semi-constants
class LoadableParameters
{
public:
Parameters() { Load(); }
const char * ProductWebSite() const { return web_site_url.c_str(); }
unsigned long HashTableSize() const { return hash_table_entries_number; }
private:
std::string web_site_url;
unsigned long hash_table_entries_number;

void Load()
{
Repository storage;
const char key_name[] = {"product_attributes"};

const char site_value_name[] = {"web_site"};
if ( ! storage.LoadString( key_name, site_value_name, &web_site_url ) )
{
const char web_site_url_default[] = {"http://myCompany.com"};
web_site_url = web_site_url_default;
}

const char hash_value_name[] = {"web_site"};
if ( ! storage.LoadUnsignedLong( key_name, value_name, &web_site_url ) )
{
const unsigned long hash_table_size_default = 37;
hash_table_entries_number = hash_table_size_default;
}
}
};


Application of semi-constants
Semi-constants are well suited for use in the families of similar products, when the value of particular parameter is different for different products. For example, the software accompanying the hardware device can have loadable reference to the device's web page. The plug-in for the host program (such as add-in module for Microsoft Office) can have loadable lowest supported version number of the host application. If features of your product are implemented as separate modules, you may make loadable list of features that are available for particular flavor of the product: product "business" has features A, B, and C, product "home" has features C and D, product "big money" has A, B, C, and D.

Where to store semi-constants
In a popular scenario, the product installation procedure stores values of the parameters inside the Windows Registry, or in the disk file. At startup, the program reads those values.
Modern network-oriented scenarios assume that values are stored on the remote server. The product support team owning the server may change the values invisibly for product users.
If your product uses the database for the customer's data, you may add a table for storing parameters of your application.
Some systems assume that user's credentials (user name and password) are stored on smart cards.
Standard way of keeping locale-specific data, such as text strings translated to target languages is to store them inside language packs as Windows Resources.

By default
Note that attempt to load a semi-constant may fail (for example, because the server is temporarily disconnected from the network). You need provide default values using named constants or encapsulated decisions described above.

Delayed load
If you will made the instance of LoadableParameters class from Listing 1 the global variable or the member of the class instantiated as a global variable, parameters will load at the program startup. If the loading of semi-constants involves long-executing procedures (such as loading data from the Internet), you may want to postpone actual loading to the moment in time when parameters will asked for a first time.

Listing 2. Delayed load of semi-constants
LoadableParameters & LoadableParametersInstance()
{
// constructed at first call of LoadableParametersInstance()
static LoadableParameters single;

return single;
// destroyed at exit from the program
}

No comments: