devxlogo

Share Data Among Objects Using the Monostate Design Pattern

Share Data Among Objects Using the Monostate Design Pattern

ertain applications need to share data among different users or among distributed instances of the same application. Using a file to store the shared data isn’t an ideal solution due to security and data integrity reasons. This month I will suggest another solution based on the monostate design pattern.


How can you ensure that all users of the same application access shared data safely?


Use the monostate design pattern to ensure safe and synchronized data sharing.

Step 1: Design
Imagine a large department store that has different departments for multimedia, clothes, and cosmetics. Such stores often enable tourists to pay in their own currencies. How can you ensure that every department has access to the same exchange rate table? Using a shared physical file might cause security and data-integrity problems. For example, the filename and its path might change; worse yet, users might access an outdated version of the file. Besides, this is an implementation detail that should be hidden from end users.

A preferable solution is to encapsulate the exchange rates in a class. You want to ensure that every user and application module gets a private object instance of the class in question while ensuring that these objects always share the same state. Furthermore, any change in the state of the class should propagate to other objects automatically and immediately. This is exactly what the monostate design pattern provides.

A monostate class is a class that implements the monostate design pattern. A monostate class contains only static data members and member functions. This way, all of its object instances share the same state.

Step 2: Implementation
We will create a monostate class, called Exchange, whose static data members represent the exchange rates of a various currencies, say Euros per $1 U.S., etc.:

class Exchange{private:static double Euro; // Euros per $1 U.S.static double GBP; // British pounds per $1 U.S.static double Yen;  // Yens per $1 U.S. //...};

The definitions of the static members outside the class also initialize them:

double Exchange::Euro=0.8630; // Euros per $1 U.S.double Exchange::GBP=0.6017; // British Pounds per $1 U.S.double Exchange::Yen= 119.34; // Yens per $1 U.S.

In the real world you’d probably use a function that reads the current exchange rates from a remote server or a database to initialize the data. For example:

double Exchange::Euro=  trade_server.get_euro_rate(now); // Euros per $1 U.S.//other currencies 

The class also contains member functions that exchange these currencies to and from U.S. dollars:

class Exchange{//public: double Euro_to_USD(double euros) const { return euros/Euro;} double US_to_Euro(double us_dollars) const { return us_dollars*Euro;} double GBP_to_USD(double pounds) const { return pounds/GBP;} double USD_to_GBP(double us_dollars) const { return us_dollars*GBP;}// };

Step 3: Usage
Now that you’ve seen the code for the class, I’ll step through how it works. Suppose a British tourist visits the cosmetics department and decides to purchase a perfume that costs $99.95. She prefers to pay cash, in pounds. The attendant types the amount 99.95 in the “Exchange $ to £” dialog box. Under the hood, the application does something like this:

int main(){ Exchange xcg;  //cosmetics dept.'s private object double pounds=xcg.USD_to_GBP(99.95);//convert $99.95 to GBP cout

The program's output is as follows:

You probably want to round the amount 60.1399 to 60.14 automatically. You can define a policies class that will write the user interface for the rounding. These policies may include rounding schemes, say up to the closest penny or in units of 5 or 10 pence. These policies should not be included in the Exchange class as it is responsible for representing the raw exchange rates only. Furthermore, while exchange rates change on a daily basis (or even by the hour), store policies are more stable. Keeping your Exchange class independent of fluctuating exchange rates will make it more stable and easier to maintain.

Monostate Muscle
I haven't shown the real strength of the monostate pattern yet. Suppose our store updates the exchange rates every hour, according to quote prices of a certain bank. To change the rate we add another class called Admin, which is a friend of class Exchange. The new exchange rate propagates swiftly to all instances of Exchange.

class Admin;class Exchange{friend class Admin;//};class Admin{public: Admin(const string &password) {} //authorize  void set_EURO(double euros) const {Exchange::Euro = euros;}  void set_GBP(double pounds) const {Exchange::GBP = pounds;}//};

Suppose the British pound exchange rate is now 0.62. The system administrator updates it like this:

Admin admin("mypassword");admin.set_GBP(0.62);

From this moment, every instance of the Exchange class is aware of the new exchange rate. If another British lady decides to buy the same perfume, she'll now have to pay 61.97 pounds:

pounds=rates.USD_to_GBP(99.95);cout

Magnificent Monostate
The monostate pattern isn't included in the de-facto pattern catalog because it was developed later. In terms of its goals, monostate is similar to the singleton pattern, albeit much simpler in terms of implementation and usage.

The use of static data members and member functions ensures that the same state is shared by all objects of the same class, regardless of their creation time. Changing a static member's value enables you to update the objects' state immediately and automatically. The implementation of the monostate class shown here isn't thread safe. However, with slight modifications you can turn it into a thread-safe class.

devxblackblue

About Our Editorial Process

At DevX, we’re dedicated to tech entrepreneurship. Our team closely follows industry shifts, new products, AI breakthroughs, technology trends, and funding announcements. Articles undergo thorough editing to ensure accuracy and clarity, reflecting DevX’s style and supporting entrepreneurs in the tech sphere.

See our full editorial policy.

About Our Journalist