Thursday, March 21, 2024

Differences between SQL and NoSQL

The table below summarizes the main differences between SQL and NoSQL databases.

SQL DatabasesNoSQL Databases
Data Storage ModelTables with fixed rows and columnsDocument: JSON documents, Key-value: key-value pairs, Wide-column: tables with rows and dynamic columns, Graph: nodes and edges
Development HistoryDeveloped in the 1970s with a focus on reducing data duplicationDeveloped in the late 2000s with a focus on scaling and allowing for rapid application change driven by agile and DevOps practices.
ExamplesOracle, MySQL, Microsoft SQL Server, and PostgreSQLDocument: MongoDB and CouchDB, Key-value: Redis and DynamoDB, Wide-column: Cassandra and HBase, Graph: Neo4j and Amazon Neptune
Primary PurposeGeneral purposeDocument: general purpose, Key-value: large amounts of data with simple lookup queries, Wide-column: large amounts of data with predictable query patterns, Graph: analyzing and traversing relationships between connected data
SchemasRigidFlexible
ScalingVertical (scale-up with a larger server)Horizontal (scale-out across commodity servers)
Multi-Record ACID TransactionsSupportedMost do not support multi-record ACID transactions. However, some — like MongoDB — do.
JoinsTypically requiredTypically not required
Data to Object MappingRequires ORM (object-relational mapping)Many do not require ORMs. MongoDB documents map directly to data structures in most popular programming languages.

What type of information is stored in a database?

Databases are used in most modern applications, whether the database is on your personal phone, computer, or the internet. An operational database system will store much of the data an application needs to function, keeping the data organized and allowing users to access the data.

If you were building an eCommerce app, some of the data you might access and store in your operational database system includes:

Customer data 

-like usernames, email addresses, and preferences.

Business data

- like product colors, prices, and ratings.

Relationship data

- like the locations of stores with a specific product in stock.

Wednesday, March 20, 2024

How Many Types of Databases Are There?

There are nearly a dozen types of database. Some of the more commonly used categories of database include:

Hierarchical Databases

Developed in the 1960s, the hierarchical database looks similar to a family tree. A single object (the “parent”) has one or more objects beneath it (the “child”). No child can have more than one parent. In exchange for the rigid and complex navigation of the parent child structure, the hierarchical database offers high performance, as there’s easy access and a quick querying time. The Windows Registry is one example of this system.

Relational Databases

Relational databases are a system designed in the 1970s. This database commonly uses Structured Query Language (SQL) for operations like creating, reading, updating, and deleting (CRUD) data.

This database stores data in discrete tables, which can be joined together by fields known as foreign keys. For example, you might have a User table that contains data about your users, and join the users table to a Purchases table, which contains data about the purchases the users have made. MySQL, Microsoft SQL Server, and Oracle are examples.

Non-Relational Databases

Non-relational management systems are commonly referred to as NoSQL databases. This type of database matured due to increasingly complex modern web applications. These databases' varieties have proliferated over the last decade. Examples include MongoDB and Redis.

Object oriented databases

Object oriented databases store and manage objects on a database server's disk. Object oriented databases are unique because associations between objects can persist. This means that object oriented programming and the querying of data across complex relationships is fast and powerful. One example of an object oriented database is MongoDB Realm, where the query language constructs native objects through your chosen SDK. Object oriented programming is the most popular programming paradigm. 

NoSQL

NoSQL is an umbrella term for any alternative system to traditional SQL databases. Sometimes, when we say NoSQL management systems, we mean any database that doesn't use a relational model. NoSQL databases use a data model that has a different structure than the rows and columns table structure used with RDBMS.

NoSQL databases are different from each other. There are four kinds of this database: 

document databases, 
key-value stores, 
column-oriented databases, and
Graph databases


Document databases

A document database stores data in JSON, BSON, or XML documents. Documents in the database can be nested. Particular elements can be indexed for faster querying.

You can access, store, and retrieve documents from your network in a form that is much closer to the data objects used in applications, which means less translation is required to use and access the data in an application. SQL data must often be assembled and disassembled when moving between applications, storage, or more than one network.

Document databases are popular with developers because they offer the flexibility to rework their document structures as needed to suit their applications. The flexibility of this database speeds development — data becomes like code and is under the control of developers. They can more easily access and use it. In SQL databases, intervention by database administrators may be required to change the structure of a database.

Document databases are usually implemented with a scale-out architecture, providing a path to the scalability of data volumes and traffic. Use cases include eCommerce platforms, trading platforms, and mobile app development.

Key-value stores

This is the simplest type of NoSQL database. Every element is stored as a key-value pair consisting of an attribute name ("key") and a value. This database is like an RDBMS with two columns: the attribute name (such as "state") and the value (such as "Alaska").

Use cases for NoSQL databases include shopping carts, user preferences, and user profiles.

Column-oriented databases

While an RDBMS stores data in rows and reads it row by row, column-oriented databases are organized as a set of columns. When you want to run analytics on a small number of columns in the network, you can read those columns directly without consuming memory with unwanted data. Columns are of the same type and benefit from more efficient compression, making reads even faster. A column-oriented database can aggregate the value of a given column (adding up sales for the year, for example). Use cases of a column-oriented database include analytics.

While column-oriented databases are great for analytics, the way they write data makes it difficult for them to be consistent as writes of all the columns in the column-oriented database require multiple write events on disk. Relational databases don't suffer from this problem as row data is written contiguously to disk.

Graph databases

A graph database focuses on the relationship between data elements. Each element is contained as a node. The connections between elements in the database are called links or relationships. Connections are first-class elements of the database, stored directly.

A graph database is optimized to capture and search the connections between elements, overcoming the overhead associated with JOINing several tables in SQL. Very few real-world business systems can survive solely on graph databases. As a result, graph databases are usually run alongside more traditional databases.

Use cases include fraud detection and social networks.

These databases are diverse in their data formats and applications. Furthermore, systems store data in different ways:

Data can be stored in a structured document, similar to JSON (JavaScript Object Notation). MongoDB is a popular document distributed database.

Data can be in a key-value format that maps a single attribute (key) to its value. Redis and Riak KV are examples. They’re typically used for simple one-to-one relationships, like associating users with preferences.

A graph datastore uses nodes to represent objects and edges to describe the relationship between them. Neo4j is one example.

These differ from RDBMS in that they can be schema-agnostic, allowing unstructured and semi-structured data in a network to be stored and processed.

Database

 A database(DB) is a collection of data in a format that can be easily accessed (Digital). A software application used to manage our DB is called DBMS (Database Management System).

Or

A database is an organized collection of data stored in a computer system and usually controlled by a database management system (DBMS).

Tuesday, May 4, 2010

Visitor Pattern

The visitor pattern is a behavioral object design pattern. The visitor pattern is used to simplify operations on groupings of related objects. These operations are performed by the visitor rather than by placing this code in the classes being visited. Since the operations are performed by the visitor rather than by the classes being visited, the operation code gets centralized in the visitor rather than being spread out across the grouping of objects, thus leading to code maintainability. The visitor pattern also avoids the use of the instanceof operator in order to perform calculations on similar classes.
In the visitor pattern, we have a Visitor interface that declares visit() methods for the various types of elements that can be visited. Concrete Visitors implement the Visitor interface's visit() methods. The visit() methods are the operations that should be performed by the visitor on an element being visited.
The related classes that will be visited implement an Element interface that declares an accept() method that takes a visitor as an argument. Concrete Elements implement the Element interface and implement the accept() method. In the accept() method, the visitor's visit() method is called with 'this', the current object of the Concrete Element type.
The elements to visit all implement the accept() method that takes a visitor as an argument. In this method, they call the visitor's visit() method with 'this'. As a result of this, an element takes a visitor and then the visitor performs its operation on the element.
Let's illustrate the visitor pattern with an example. First, we'll define a NumberVisitor interface. This interface declares three visit methods which take different types as arguments. Note that if we only wrote one visit method, we'd have to use the instanceof operator or a similar technique to handle the different element types. However, since we have separate visit methods, we don't need the instanceof operator, since each visit method handles a different type.

NumberVisitor.java

package com.cakes;

import java.util.List;

public interface NumberVisitor {

 public void visit(TwoElement twoElement);

 public void visit(ThreeElement threeElement);

 public void visit(List elementList);

}
All of the elements classes to be visited will implement the NumberElement interface. This interface has a single method that takes a NumberVisitor as an argument.

NumberElement.java

package com.cakes;

public interface NumberElement {

 public void accept(NumberVisitor visitor);

}
Let's create a TwoElement class that implements NumberElement. It has two int fields. Its accept() method calls the visitor's visit() method with 'this'. The operator to be performed on TwoElement is performed by the visitor.

TwoElement.java

package com.cakes;

public class TwoElement implements NumberElement {

 int a;
 int b;

 public TwoElement(int a, int b) {
  this.a = a;
  this.b = b;
 }

 @Override
 public void accept(NumberVisitor visitor) {
  visitor.visit(this);
 }

}
The ThreeElement class is similar to TwoElement, except that it has three int fields.

ThreeElement.java

package com.cakes;

public class ThreeElement implements NumberElement {

 int a;
 int b;
 int c;

 public ThreeElement(int a, int b, int c) {
  this.a = a;
  this.b = b;
  this.c = c;
 }

 @Override
 public void accept(NumberVisitor visitor) {
  visitor.visit(this);
 }

}
Now, let's create a visitor called SumVisitor that implements the NumberVisitor interface. For TwoElement and ThreeElement objects, this visitor will sum up the int fields. For a List of NumElements (ie, TwoElement and ThreeElement objects), this visitor will iterate over the elements and call their accept() methods. As a result of this, the visitor will perform visit operations on all the TwoElement and ThreeElement objects that make up the list, since the call to accept() in turn calls the visitor's visit methods for the TwoElement and ThreeElement objects. 

SumVisitor.java

package com.cakes; import java.util.List; public class SumVisitor implements NumberVisitor { @Override public void visit(TwoElement twoElement) { int sum = twoElement.a + twoElement.b; System.out.println(twoElement.a + "+" + twoElement.b + "=" + sum); } @Override public void visit(ThreeElement threeElement) { int sum = threeElement.a + threeElement.b + threeElement.c; System.out.println(threeElement.a + "+" + threeElement.b + "+" + threeElement.c + "=" + sum); } @Override public void visit(List elementList) { for (NumberElement ne : elementList) { ne.accept(this); } } } Here is another visitor, TotalSumVisitor. In addition to summing up the int fields and displaying the sum, this visitor will keep track of the total sums of all the elements that are visited.

TotalSumVisitor.java

package com.cakes; import java.util.List; public class TotalSumVisitor implements NumberVisitor { int totalSum = 0; @Override public void visit(TwoElement twoElement) { int sum = twoElement.a + twoElement.b; System.out.println("Adding " + twoElement.a + "+" + twoElement.b + "=" + sum + " to total"); totalSum += sum; } @Override public void visit(ThreeElement threeElement) { int sum = threeElement.a + threeElement.b + threeElement.c; System.out.println("Adding " + threeElement.a + "+" + threeElement.b + "+" + threeElement.c + "=" + sum + " to total"); totalSum += sum; } @Override public void visit(List elementList) { for (NumberElement ne : elementList) { ne.accept(this); } } public int getTotalSum() { return totalSum; } } Let's see the visitor pattern in action. The Demo class creates two TwoElement objects and one ThreeElement object. It creates a list of NumberElements and adds the TwoElement object and the ThreeElement object to the list. Next, we create a SumVisitor and we visit the list with the SumVisitor. After this, we create a TotalSumVisitor and visit the list with the TotalSumVisitor. We display the total sum via the call to TotalSumVisitor's getTotalSum() method.

Demo.java

package com.cakes; import java.util.ArrayList; import java.util.List; public class Demo { public static void main(String[] args) { TwoElement two1 = new TwoElement(3, 3); TwoElement two2 = new TwoElement(2, 7); ThreeElement three1 = new ThreeElement(3, 4, 5); List numberElements = new ArrayList(); numberElements.add(two1); numberElements.add(two2); numberElements.add(three1); System.out.println("Visiting element list with SumVisitor"); NumberVisitor sumVisitor = new SumVisitor(); sumVisitor.visit(numberElements); System.out.println("\nVisiting element list with TotalSumVisitor"); TotalSumVisitor totalSumVisitor = new TotalSumVisitor(); totalSumVisitor.visit(numberElements); System.out.println("Total sum:" + totalSumVisitor.getTotalSum()); } } The console output of executing Demo is shown here.

Console Output

Visiting element list with SumVisitor 3+3=6 2+7=9 3+4+5=12 Visiting element list with TotalSumVisitor Adding 3+3=6 to total Adding 2+7=9 to total Adding 3+4+5=12 to total Total sum:27 Notice that if we'd like to perform new operations on the grouping of elements, all we would need to do is write a new visitor class. We would not have to make any additions to the existing element classes, since they provide the data but none of the code for the operations.

Template Method Pattern

The template method pattern is a behavioral class pattern. A behavioral class pattern uses inheritance for distribution of behavior. In the template method pattern, a method (the 'template method') defines the steps of an algorithm. The implementation of these steps (ie, methods) can be deferred to subclasses. Thus, a particular algorithm is defined in the template method, but the exact steps of this algorithm can be defined in subclasses. The template method is implemented in an abstract class. The steps (methods) of the algorithm are declared in the abstract class, and the methods whose implementations are to be delegated to subclasses are declared abstract.
Here is an example of the template method pattern. Meal is an abstract class with a template method called doMeal() that defines the steps involved in a meal. We declare the method as final so that it can't be overridden. The algorithm defined by doMeal() consists of four steps: prepareIngredients(), cook(), eat(), and cleanUp(). The eat() method is implemented although subclasses can override the implementation. The prepareIngredients(), cook(), and cleanUp() methods are are declared abstract so that subclasses need to implement them.

Meal.java

package com.cakes;

public abstract class Meal {

 // template method
 public final void doMeal() {
  prepareIngredients();
  cook();
  eat();
  cleanUp();
 }

 public abstract void prepareIngredients();

 public abstract void cook();

 public void eat() {
  System.out.println("Mmm, that's good");
 }

 public abstract void cleanUp();

}
The HamburgerMeal class extends Meal and implements Meal's three abstract methods.

HamburgerMeal.java

package com.cakes;

public class HamburgerMeal extends Meal {

 @Override
 public void prepareIngredients() {
  System.out.println("Getting burgers, buns, and french fries");
 }

 @Override
 public void cook() {
  System.out.println("Cooking burgers on grill and fries in oven");
 }

 @Override
 public void cleanUp() {
  System.out.println("Throwing away paper plates");
 }

}
The TacoMeal class implements Meal's three abstract methods and also overrides the eat() method.

TacoMeal.java

package com.cakes;

public class TacoMeal extends Meal {

 @Override
 public void prepareIngredients() {
  System.out.println("Getting ground beef and shells");
 }

 @Override
 public void cook() {
  System.out.println("Cooking ground beef in pan");
 }

 @Override
 public void eat() {
  System.out.println("The tacos are tasty");
 }

 @Override
 public void cleanUp() {
  System.out.println("Doing the dishes");
 }

}
The Demo class creates a HamburgerMeal object and calls its doMeal() method. It creates a TacoMeal object and calls doMeal() on the TacoMeal object.

Demo.java

package com.cakes;

public class Demo {

 public static void main(String[] args) {

  Meal meal1 = new HamburgerMeal();
  meal1.doMeal();

  System.out.println();

  Meal meal2 = new TacoMeal();
  meal2.doMeal();

 }

}
The console output of the execution of Demo is shown here.

Console Output

Getting burgers, buns, and french fries
Cooking burgers on grill and fries in oven
Mmm, that's good
Throwing away paper plates

Getting ground beef and shells
Cooking ground beef in pan
The tacos are tasty
Doing the dishes
As you can see, the template method design pattern allows us to define the steps in an algorithm and pass the implementation of these steps to subclasses.

Startergy Pattern

The strategy pattern is a behavioral object design pattern. In the strategy pattern, different algorithms are represented as Concrete Strategy classes, and they share a common Strategy interface. A Context object contains a reference to a Strategy. By changing the Context's Strategy, different behaviors can be obtained. Although these behaviors are different, the different strategies all operate on data from the Context.
The strategy pattern is one way that composition can be used as an alternative to subclassing. Rather than providing different behaviors via subclasses overriding methods in superclasses, the strategy pattern allows different behaviors to be placed in Concrete Strategy classes which share the common Strategy interface. A Context class is composed of a reference to a Strategy.
Here is an example of the strategy pattern. First, we'll define a Strategy interface. It declares a checkTemperature() method.

Strategy.java

package com.cakes;

public interface Strategy {

 boolean checkTemperature(int temperatureInF);

}
The HikeStrategy class is a concrete strategy class that implements the Strategy interface. The checkTemperature method is implemented so that if the temperature is between 50 and 90, it returns true. Otherwise it returns false.

HikeStrategy.java

package com.cakes;

public class HikeStrategy implements Strategy {

 @Override
 public boolean checkTemperature(int temperatureInF) {
  if ((temperatureInF >= 50) && (temperatureInF <= 90)) {
   return true;
  } else {
   return false;
  }
 }

}
The SkiStrategy implements the Strategy interface. If the temperature is 32 or less, the checkTemperature method returns true. Otherwise it returns false.

SkiStrategy.java

package com.cakes;

public class SkiStrategy implements Strategy {

 @Override
 public boolean checkTemperature(int temperatureInF) {
  if (temperatureInF <= 32) {
   return true;
  } else {
   return false;
  }
 }

}
The Context class contains a temperature and a reference to a Strategy. The Strategy can be changed, resulting in different behavior that operates on the same data in the Context. The result of this can be obtained from the Context via the getResult() method.

Context.java

package com.cakes;

public class Context {

 int temperatureInF;
 Strategy strategy;

 public Context(int temperatureInF, Strategy strategy) {
  this.temperatureInF = temperatureInF;
  this.strategy = strategy;
 }

 public void setStrategy(Strategy strategy) {
  this.strategy = strategy;
 }

 public int getTemperatureInF() {
  return temperatureInF;
 }

 public boolean getResult() {
  return strategy.checkTemperature(temperatureInF);
 }

}
The Demo class creates a Context object with a temperature of 60 and with a SkiStrategy. It displays the temperature from the context and whether that temperature is OK for skiing. After that, it sets the Strategy in the Context to HikeStrategy. It then displays the temperature from the context and whether that temperature is OK for hiking. 

Demo.java

package com.cakes; public class Demo { public static void main(String[] args) { int temperatureInF = 60; Strategy skiStrategy = new SkiStrategy(); Context context = new Context(temperatureInF, skiStrategy); System.out.println("Is the temperature (" + context.getTemperatureInF() + "F) good for skiing? " + context.getResult()); Strategy hikeStrategy = new HikeStrategy(); context.setStrategy(hikeStrategy); System.out.println("Is the temperature (" + context.getTemperatureInF() + "F) good for hiking? " + context.getResult()); } } The console output of executing Demo is shown here.

Console Output

Is the temperature (60F) good for skiing? false Is the temperature (60F) good for hiking? true

State Pattern

The state pattern is a behavioral object design pattern. The idea behind the state pattern is for an object to change its behavior depending on its state. In the state pattern, we have a Context class, and this class has a State reference to a Concrete State instance. The State interface declares particular methods that represent the behaviors of a particular state. Concrete States implement these behaviors. By changing a Context's Concrete State, we change its behavior. In essence, in the state pattern, a class (the Context) is supposed to behave like different classes depending on its state. The state pattern avoids the use of switch and if statements to change behavior.
Let's look at an example of the state pattern. First off, we'll define the EmotionalState interface. It declares two methods, sayHello() and sayGoodbye().

EmotionalState.java

package com.cakes;

// State
public interface EmotionalState {

 public String sayHello();

 public String sayGoodbye();

}
The HappyState class is a Concrete State that implements sayHello() and sayGoodbye() of EmotionalState. These messages are cheerful (representing a happy state).

HappyState.java

package com.cakes;

// Concrete State
public class HappyState implements EmotionalState {

 @Override
 public String sayGoodbye() {
  return "Bye, friend!";
 }

 @Override
 public String sayHello() {
  return "Hello, friend!";
 }

}
The SadState class also implements the EmotionalState interface. The messages are sad (representing a sad state).

SadState.java

package com.cakes;

//Concrete State
public class SadState implements EmotionalState {

 @Override
 public String sayGoodbye() {
  return "Bye. Sniff, sniff.";
 }

 @Override
 public String sayHello() {
  return "Hello. Sniff, sniff.";
 }

}
The Person class is the Context class. It contains an EmotionalState reference to a concrete state. In this example, we have Person implement the EmotionalState reference, and we pass the calls to Person's sayHello() and sayGoodbye() methods on to the corresponding methods on the emotionalState reference. As a result of this, a Person object behaves differently depending on the state of Person (ie, the current EmotionalState reference).

Person.java

package com.cakes;

// Context
public class Person implements EmotionalState {

 EmotionalState emotionalState;

 public Person(EmotionalState emotionalState) {
  this.emotionalState = emotionalState;
 }

 public void setEmotionalState(EmotionalState emotionalState) {
  this.emotionalState = emotionalState;
 }

 @Override
 public String sayGoodbye() {
  return emotionalState.sayGoodbye();
 }

 @Override
 public String sayHello() {
  return emotionalState.sayHello();
 }

}
The Demo class demonstrates the state pattern. First, it creates a Person object with a HappyState object. We display the results of sayHello() and sayGoodbyte() when the person object is in the happy state. Next, we change the person object's state with a SadState object. We display the results of sayHello() and sayGoodbyte(), and we see that in the sad state, the person object's behavior is different.

Demo.java

package com.cakes; public class Demo { public static void main(String[] args) { Person person = new Person(new HappyState()); System.out.println("Hello in happy state: " + person.sayHello()); System.out.println("Goodbye in happy state: " + person.sayGoodbye()); person.setEmotionalState(new SadState()); System.out.println("Hello in sad state: " + person.sayHello()); System.out.println("Goodbye in sad state: " + person.sayGoodbye()); } } The console output of executing Demo is shown here.

Console Output

Hello in happy state: Hello, friend! Goodbye in happy state: Bye, friend! Hello in sad state: Hello. Sniff, sniff. Goodbye in sad state: Bye. Sniff, sniff. Note that we don't necessarily need to have the Context (ie, Person) implement the EmotionalState interface. The behavioral changes could have been internal to the Context rather than exposing EmotionalState's methods to the outside. However, having the Context class implement the State interface allows us to directly access the different behaviors that result from the different states of the Context.

Observer Pattern

The observer pattern is a behavioral object design pattern. In the observer pattern, an object called the subject maintains a collection of objects called observers. When the subject changes, it notifies the observers. Observers can be added or removed from the collection of observers in the subject. The changes in state of the subject can be passed to the observers so that the observers can change their own state to reflect this change.
The subject has an interface that defines methods for attaching and detaching observers from the subject's collection of observers. This interface also features a notification method. This method should be called when the state of the subject changes. This notifies the observers that the subject's state has changed. The observers have an interface with a method to update the observer. This update method is called for each observer in the subject's notification method. Since this communication occurs via an interface, any concrete observer implementing the observer interface can be updated by the subject. This results in loose coupling between the subject and the observer classes.
Now we'll look at an example of the observer pattern. We'll start by creating an interface for the subject called WeatherSubject. This will declare three methods: addObserver(), removeObserver(), and doNotify().

WeatherSubject.java

package com.cakes;

public interface WeatherSubject {

 public void addObserver(WeatherObserver weatherObserver);

 public void removeObserver(WeatherObserver weatherObserver);

 public void doNotify();

}
We'll also create an interface for the observers called WeatherObserver. It features one method, a doUpdate() method.

WeatherObserver.java

package com.cakes;

public interface WeatherObserver {

 public void doUpdate(int temperature);
 
}
The WeatherStation class implements WeatherSubject. It is our subject class. It maintains a set of WeatherObservers which are added via addObserver() and removed via removeObserver(). When WeatherSubject's state changes via setTemperature(), the doNotify() method is called, which contacts all the WeatherObservers with the temperature via their doUpdate() methods.

WeatherStation.java

package com.cakes;

import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;

public class WeatherStation implements WeatherSubject {

 Set weatherObservers;
 int temperature;

 public WeatherStation(int temperature) {
  weatherObservers = new HashSet();
  this.temperature = temperature;
 }

 @Override
 public void addObserver(WeatherObserver weatherObserver) {
  weatherObservers.add(weatherObserver);
 }

 @Override
 public void removeObserver(WeatherObserver weatherObserver) {
  weatherObservers.remove(weatherObserver);
 }

 @Override
 public void doNotify() {
  Iterator it = weatherObservers.iterator();
  while (it.hasNext()) {
   WeatherObserver weatherObserver = it.next();
   weatherObserver.doUpdate(temperature);
  }
 }

 public void setTemperature(int newTemperature) {
  System.out.println("\nWeather station setting temperature to " + newTemperature);
  temperature = newTemperature;
  doNotify();
 }

}
WeatherCustomer1 is an observer that implements WeatherObserver. Its doUpdate() method gets the current temperature from the WeatherStation and displays it.

WeatherCustomer1.java

package com.cakes; public class WeatherCustomer1 implements WeatherObserver { @Override public void doUpdate(int temperature) { System.out.println("Weather customer 1 just found out the temperature is:" + temperature); } } WeatherCustomer2 performs similar functionality as WeatherCustomer1.

WeatherCustomer2.java

package com.cakes; public class WeatherCustomer2 implements WeatherObserver { @Override public void doUpdate(int temperature) { System.out.println("Weather customer 2 just found out the temperature is:" + temperature); } } The Demo class demonstrates the observer pattern. It creates a WeatherStation and then a WeatherCustomer1 and a WeatherCustomer2. The two customers are added as observers to the weather station. Then the setTemperature() method of the weather station is called. This changes the state of the weather station and the customers are notified of this temperature update. Next, the WeatherCustomer1 object is removed from the station's collection of observers. Then, the setTemperature() method is called again. This results in the notification of the WeatherCustomer2 object.

Demo.java

package com.cakes; public class Demo { public static void main(String[] args) { WeatherStation weatherStation = new WeatherStation(33); WeatherCustomer1 wc1 = new WeatherCustomer1(); WeatherCustomer2 wc2 = new WeatherCustomer2(); weatherStation.addObserver(wc1); weatherStation.addObserver(wc2); weatherStation.setTemperature(34); weatherStation.removeObserver(wc1); weatherStation.setTemperature(35); } } The console output of executing Demo is shown here.

Console Output

Weather station setting temperature to 34 Weather customer 2 just found out the temperature is:34 Weather customer 1 just found out the temperature is:34 Weather station setting temperature to 35 Weather customer 2 just found out the temperature is:35 In a more advanced case, we might have given each observer a reference to the weather station object. This could allow the observer the ability to compare the state of the subject in detail with its own state and make any necessary updates to its own state.

Momento Pattern

The memento pattern is a behavioral design pattern. The memento pattern is used to store an object's state so that this state can be restored at a later point. The saved state data in the memento object is not accessible outside of the object to be saved and restored. This protects the integrity of the saved state data.
In this pattern, an Originator class represents the object whose state we would like to save. A Memento class represents an object to store the state of the Originator. The Memento class is typically a private inner class of the Originator. As a result, the Originator has access to the fields of the memento, but outside classes do not have access to these fields. This means that state information can be transferred between the Memento and the Originator within the Originator class, but outside classes do not have access to the state data stored in the Memento.
The memento pattern also utilizes a Caretaker class. This is the object that is responsible for storing and restoring the Originator's state via a Memento object. Since the Memento is a private inner class, the Memento class type is not visible to the Caretaker. As a result, the Memento object needs to be stored as an Object within the Caretaker.

Now, let's look at an example. The DietInfo class is our Originator class. We'd like to be able to save and restore its state. It contains 3 fields: a dieter name field, the day number of the diet, and the weight of the dieter on the specified day of the diet.
This class contains a private inner class called Memento. This is our Memento class that is used to save the state of DietInfo. Memento has 3 fields representing the dieter name, the day number, and the weight of the dieter.
Notice the save() method of DietInfo. This creates and returns a Memento object. This returned Memento object gets stored by the caretaker. Note that DietInfo.Memento is not visible, so the caretaker can't reference DietInfo.Memento. Instead, it stores the reference as an Object.
The restore() method of DietInfo is used to restore the state of the DietInfo. The caretaker passes in the Memento (as an Object). The memento is cast to a Memento object and then the DietInfo object's state is restored by copying over the values from the memento.

DietInfo.java

package com.cakes;

// originator - object whose state we want to save
public class DietInfo {

 String personName;
 int dayNumber;
 int weight;

 public DietInfo(String personName, int dayNumber, int weight) {
  this.personName = personName;
  this.dayNumber = dayNumber;
  this.weight = weight;
 }

 public String toString() {
  return "Name: " + personName + ", day number: " + dayNumber + ", weight: " + weight;
 }

 public void setDayNumberAndWeight(int dayNumber, int weight) {
  this.dayNumber = dayNumber;
  this.weight = weight;
 }

 public Memento save() {
  return new Memento(personName, dayNumber, weight);
 }

 public void restore(Object objMemento) {
  Memento memento = (Memento) objMemento;
  personName = memento.mementoPersonName;
  dayNumber = memento.mementoDayNumber;
  weight = memento.mementoWeight;
 }

 // memento - object that stores the saved state of the originator
 private class Memento {
  String mementoPersonName;
  int mementoDayNumber;
  int mementoWeight;

  public Memento(String personName, int dayNumber, int weight) {
   mementoPersonName = personName;
   mementoDayNumber = dayNumber;
   mementoWeight = weight;
  }
 }
}
DietInfoCaretaker is the caretaker class that is used to store the state (ie, the memento) of a DietInfo object (ie, the originator). The memento is stored as an object since DietInfo.Memento is not visible to the caretaker. This protects the integrity of the data stored in the Memento object. The caretaker's saveState() method saves the state of the DietInfo object. The caretaker's restoreState() method restores the state of the DietInfo object.

DietInfoCaretaker.java

package com.cakes;

// caretaker - saves and restores a DietInfo object's state via a memento
// note that DietInfo.Memento isn't visible to the caretaker so we need to cast the memento to Object
public class DietInfoCaretaker {

 Object objMemento;

 public void saveState(DietInfo dietInfo) {
  objMemento = dietInfo.save();
 }

 public void restoreState(DietInfo dietInfo) {
  dietInfo.restore(objMemento);
 }

}
 
he MementoDemo class demonstrates the memento pattern. It creates a
caretaker and then a DietInfo object. The DietInfo object's state is
changed and displayed. At one point, the caretaker saves the state of
the DietInfo object. After this, the DietInfo object's state is further
changed and displayed. After this, the caretaker restores the state of
the DietInfo object. We verify this restoration by displaying the
DietInfo object's state. 

MementoDemo.java

package com.cakes; public class MementoDemo { public static void main(String[] args) { // caretaker DietInfoCaretaker dietInfoCaretaker = new DietInfoCaretaker(); // originator DietInfo dietInfo = new DietInfo("Fred", 1, 100); System.out.println(dietInfo); dietInfo.setDayNumberAndWeight(2, 99); System.out.println(dietInfo); System.out.println("Saving state."); dietInfoCaretaker.saveState(dietInfo); dietInfo.setDayNumberAndWeight(3, 98); System.out.println(dietInfo); dietInfo.setDayNumberAndWeight(4, 97); System.out.println(dietInfo); System.out.println("Restoring saved state."); dietInfoCaretaker.restoreState(dietInfo); System.out.println(dietInfo); } } The console output of the execution of MementoDemo is shown here. Notice how the state changes, and how we are able to save and restore the state of the originator via the caretaker's reference to the memento.

Console Output

Name: Fred, day number: 1, weight: 100 Name: Fred, day number: 2, weight: 99 Saving state. Name: Fred, day number: 3, weight: 98 Name: Fred, day number: 4, weight: 97 Restoring saved state. Name: Fred, day number: 2, weight: 99
 

Mediator Pattern-1

The mediator pattern is a behavioral object design pattern. The mediator pattern centralizes communication between objects into a mediator object. This centralization is useful since it localizes in one place the interactions between objects, which can increase code maintainability, especially as the number of classes in an application increases. Since communication occurs with the mediator rather than directly with other objects, the mediator pattern results in a loose coupling of objects.
The classes that communicate with the mediator are known as Colleagues. The mediator implementation is known as the Concrete Mediator. The mediator can have an interface that spells out the communication with Colleages. Colleagues know their mediator, and the mediator knows its colleagues.
Now, let's look at an example of this pattern. We'll create a Mediator class (without implementing a mediator interface in this example). This mediator will mediate the communication between two buyers (a Swedish buyer and a French buyer), an American seller, and a currency converter.
The Mediator has references to the two buyers, the seller, and the converter. It has methods so that objects of these types can be registered. It also has a placeBid() method. This method takes a bid amount and a unit of currency as parameters. It converts this amount to a dollar amount via communication with the dollarConverter. It then asks the seller if the bid has been accepted, and it returns the answer.

Mediator.java

package com.cakes;

public class Mediator {

 Buyer swedishBuyer;
 Buyer frenchBuyer;
 AmericanSeller americanSeller;
 DollarConverter dollarConverter;

 public Mediator() {
 }

 public void registerSwedishBuyer(SwedishBuyer swedishBuyer) {
  this.swedishBuyer = swedishBuyer;
 }

 public void registerFrenchBuyer(FrenchBuyer frenchBuyer) {
  this.frenchBuyer = frenchBuyer;
 }

 public void registerAmericanSeller(AmericanSeller americanSeller) {
  this.americanSeller = americanSeller;
 }

 public void registerDollarConverter(DollarConverter dollarConverter) {
  this.dollarConverter = dollarConverter;
 }

 public boolean placeBid(float bid, String unitOfCurrency) {
  float dollarAmount = dollarConverter.convertCurrencyToDollars(bid, unitOfCurrency);
  return americanSeller.isBidAccepted(dollarAmount);
 }
}
Here is the Buyer class. The SwedishBuyer and FrenchBuyer classes are subclasses of Buyer. The buyer has a unit of currency as a field, and it also has a reference to the mediator. The Buyer class has a attemptToPurchase() method. This method submits a bid to the mediator's placeBid() method. It returns the mediator's response.

Buyer.java

package com.cakes;

public class Buyer {

 Mediator mediator;
 String unitOfCurrency;

 public Buyer(Mediator mediator, String unitOfCurrency) {
  this.mediator = mediator;
  this.unitOfCurrency = unitOfCurrency;
 }

 public boolean attemptToPurchase(float bid) {
  System.out.println("Buyer attempting a bid of " + bid + " " + unitOfCurrency);
  return mediator.placeBid(bid, unitOfCurrency);
 }
}
The SwedishBuyer class is a subclass of Buyer. In the constructor, we set the unitOfCurrency to be "krona". We also register the SwedishBuyer with the mediator so that the mediator knows about the SwedishBuyer object.

SwedishBuyer.java

package com.cakes;

public class SwedishBuyer extends Buyer {

 public SwedishBuyer(Mediator mediator) {
  super(mediator, "krona");
  this.mediator.registerSwedishBuyer(this);
 }
}
The FrenchBuyer class is similar to the SwedishBuyer class, except the unitOfCurrency is "euro", and it registers with the mediator as the FrenchBuyer.

FrenchBuyer.java

package com.cakes;

public class FrenchBuyer extends Buyer {

 public FrenchBuyer(Mediator mediator) {
  super(mediator, "euro");
  this.mediator.registerFrenchBuyer(this);
 }
}

In the constructor of the AmericanSeller class, the class gets a reference to the mediator and the priceInDollars gets set. This is the price of some good being sold. The seller registers with the mediator as the AmericanSeller. The seller's isBidAccepted() method takes a bid (in dollars). If the bid is over the price (in dollars), the bid is accepted and true is returned. Otherwise, false is returned.

AmericanSeller.java

package com.cakes;

public class AmericanSeller {

 Mediator mediator;
 float priceInDollars;

 public AmericanSeller(Mediator mediator, float priceInDollars) {
  this.mediator = mediator;
  this.priceInDollars = priceInDollars;
  this.mediator.registerAmericanSeller(this);
 }

 public boolean isBidAccepted(float bidInDollars) {
  if (bidInDollars >= priceInDollars) {
   System.out.println("Seller accepts the bid of " + bidInDollars + " dollars\n");
   return true;
  } else {
   System.out.println("Seller rejects the bid of " + bidInDollars + " dollars\n");
   return false;
  }
 }

}
The DollarConverter class is another colleague class. When created, it gets a reference to the mediator and registers itself with the mediator as the DollarConverter. This class has methods to convert amounts in euros and kronor to dollars.

DollarConverter.java

package com.cakes;

public class DollarConverter {

 Mediator mediator;

 public static final float DOLLAR_UNIT = 1.0f;
 public static final float EURO_UNIT = 0.7f;
 public static final float KRONA_UNIT = 8.0f;

 public DollarConverter(Mediator mediator) {
  this.mediator = mediator;
  mediator.registerDollarConverter(this);
 }

 private float convertEurosToDollars(float euros) {
  float dollars = euros * (DOLLAR_UNIT / EURO_UNIT);
  System.out.println("Converting " + euros + " euros to " + dollars + " dollars");
  return dollars;
 }

 private float convertKronorToDollars(float kronor) {
  float dollars = kronor * (DOLLAR_UNIT / KRONA_UNIT);
  System.out.println("Converting " + kronor + " kronor to " + dollars + " dollars");
  return dollars;
 }

 public float convertCurrencyToDollars(float amount, String unitOfCurrency) {
  if ("krona".equalsIgnoreCase(unitOfCurrency)) {
   return convertKronorToDollars(amount);
  } else {
   return convertEurosToDollars(amount);
  }
 }
}
The Demo class demonstrates our mediator pattern. It creates a SwedishBuyer object and a FrenchBuyer object. It creates an AmericanSeller object with a selling price set to 10 dollars. It then creates a DollarConverter. All of these objects register themselves with the mediator in their constructors. The Swedish buyer starts with a bid of 55 kronor and keeps bidding up in increments of 15 kronor until the bid is accepted. The French buyer starts bidding at 3 euros and keeps bidding in increments of 1.50 euros until the bid is accepted.

Demo.java

package com.cakes;

public class Demo {

 public static void main(String[] args) {

  Mediator mediator = new Mediator();

  Buyer swedishBuyer = new SwedishBuyer(mediator);
  Buyer frenchBuyer = new FrenchBuyer(mediator);
  float sellingPriceInDollars = 10.0f;
  AmericanSeller americanSeller = new AmericanSeller(mediator, sellingPriceInDollars);
  DollarConverter dollarConverter = new DollarConverter(mediator);

  float swedishBidInKronor = 55.0f;
  while (!swedishBuyer.attemptToPurchase(swedishBidInKronor)) {
   swedishBidInKronor += 15.0f;
  }

  float frenchBidInEuros = 3.0f;
  while (!frenchBuyer.attemptToPurchase(frenchBidInEuros)) {
   frenchBidInEuros += 1.5f;
  }

 }

}
The console output of the execution of Demo is shown here.

Console Output

Buyer attempting a bid of 55.0 krona
Converting 55.0 kronor to 6.875 dollars
Seller rejects the bid of 6.875 dollars

Buyer attempting a bid of 70.0 krona
Converting 70.0 kronor to 8.75 dollars
Seller rejects the bid of 8.75 dollars

Buyer attempting a bid of 85.0 krona
Converting 85.0 kronor to 10.625 dollars
Seller accepts the bid of 10.625 dollars

Buyer attempting a bid of 3.0 euro
Converting 3.0 euros to 4.285714 dollars
Seller rejects the bid of 4.285714 dollars

Buyer attempting a bid of 4.5 euro
Converting 4.5 euros to 6.4285717 dollars
Seller rejects the bid of 6.4285717 dollars

Buyer attempting a bid of 6.0 euro
Converting 6.0 euros to 8.571428 dollars
Seller rejects the bid of 8.571428 dollars

Buyer attempting a bid of 7.5 euro
Converting 7.5 euros to 10.714286 dollars
Seller accepts the bid of 10.714286 dollars
In this example of the mediator pattern, notice that all communication between our objects (buyers, seller, and converter) occurs via the mediator. The mediator pattern helps reduce the number of object references needed (via composition) as classes proliferate in a project as a project grows.

Monday, May 3, 2010

Mediator Pattern

With the mediator pattern communication between objects is encapsulated with a mediator object. Objects no longer communicate directly with each other, but instead communicate through the mediator. This reduces the dependencies between communicating objects, thereby lowering the coupling.
Mediator Pattern

Intent


  • Define an object that encapsulates how a set of objects interact. Mediator promotes loose coupling by keeping objects from referring to each other explicitly, and it lets you vary their interaction independently.
  • Design an intermediary to decouple many peers.
  • Promote the many-to-many relationships between interacting peers to “full object status”.

Problem


We want to design reusable components, but dependencies between the potentially reusable pieces demonstrates the “spaghetti code” phenomenon (trying to scoop a single serving results in an “all or nothing clump”).

Discussion


In Unix, permission to access system resources is managed at three levels of granularity: world, group, and owner. A group is a collection of users intended to model some functional affiliation. Each user on the system can be a member of one or more groups, and each group can have zero or more users assigned to it. Next figure shows three users that are assigned to all three groups.
Mediator example

If we were to model this in software, we could decide to have User objects coupled to Group objects, and Group objects coupled to User objects. Then when changes occur, both classes and all their instances would be affected.

An alternate approach would be to introduce “an additional level of indirection” - take the mapping of users to groups and groups to users, and make it an abstraction unto itself. This offers several advantages: Users and Groups are decoupled from one another, many mappings can easily be maintained and manipulated simultaneously, and the mapping abstraction can be extended in the future by defining derived classes.
Mediator example

Partitioning a system into many objects generally enhances reusability, but proliferating interconnections between those objects tend to reduce it again. The mediator object: encapsulates all interconnections, acts as the hub of communication, is responsible for controlling and coordinating the interactions of its clients, and promotes loose coupling by keeping objects from referring to each other explicitly.

The Mediator pattern promotes a “many-to-many relationship network” to “full object status”. Modelling the inter-relationships with an object enhances encapsulation, and allows the behavior of those inter-relationships to be modified or extended through subclassing.

An example where Mediator is useful is the design of a user and group capability in an operating system. A group can have zero or more users, and, a user can be a member of zero or more groups. The Mediator pattern provides a flexible and non-invasive way to associate and manage users and groups.

Structure

Mediator scheme


Colleagues (or peers) are not coupled to one another. Each talks to the Mediator, which in turn knows and conducts the orchestration of the others. The “many to many” mapping between colleagues that would otherwise exist, has been “promoted to full object status”. This new abstraction provides a locus of indirection where additional leverage can be hosted.

Mediator scheme

Example


The Mediator defines an object that controls how a set of objects interact. Loose coupling between colleague objects is achieved by having colleagues communicate with the Mediator, rather than with each other. The control tower at a controlled airport demonstrates this pattern very well. The pilots of the planes approaching or departing the terminal area communicate with the tower rather than explicitly communicating with one another. The constraints on who can take off or land are enforced by the tower. It is important to note that the tower does not control the whole flight. It exists only to enforce constraints in the terminal area.
Mediator example

Check list


  1. Identify a collection of interacting objects that would benefit from mutual decoupling.
  2. Encapsulate those interactions in the abstraction of a new class.
  3. Create an instance of that new class and rework all “peer” objects to interact with the Mediator only.
  4. Balance the principle of decoupling with the principle of distributing responsibility evenly.
  5. Be careful not to create a “controller” or “god” object.

Rules of thumb


  • Chain of Responsibility, Command, Mediator, and Observer, address how you can decouple senders and receivers, but with different trade-offs. Chain of Responsibility passes a sender request along a chain of potential receivers. Command normally specifies a sender-receiver connection with a subclass. Mediator has senders and receivers reference each other indirectly. Observer defines a very decoupled interface that allows for multiple receivers to be configured at run-time.
  • Mediator and Observer are competing patterns. The difference between them is that Observer distributes communication by introducing “observer” and “subject” objects, whereas a Mediator object encapsulates the communication between other objects. We’ve found it easier to make reusable Observers and Subjects than to make reusable Mediators.
  • On the other hand, Mediator can leverage Observer for dynamically registering colleagues and communicating with them.
  • Mediator is similar to Facade in that it abstracts functionality of existing classes. Mediator abstracts/centralizes arbitrary communication between colleague objects, it routinely “adds value”, and it is known/referenced by the colleague objects (i.e. it defines a multidirectional protocol). In contrast, Facade defines a simpler interface to a subsystem, it doesn’t add new functionality, and it is not known by the subsystem classes (i.e. it defines a unidirectional protocol where it makes requests of the subsystem classes but not vice versa).

Iterator Pattern


Definition

Provide a way to move through a list of collection or aggregated objects without knowing its internal representations.

Where to use & benefits

  • Use a standard interface to represent data objects.
  • Use s standard iterator built in each standard collection, like List, Sort, or Map.
  • Need to distinguish variations in the traversal of an aggregate.
  • Similar to Enumeration class, but more effective.
  • Need to filter out some info from an aggregated collection.

Example

Employee is an interface, Manager, PieceWorker, HourlyWorker and CommissionWorker are implementation classes of interface Employee. EmployeeTest class will create a list and use a built-in iterator of ArrayList class to traverse the members of the list.
import java.util.*;
interface Employee {   
    public abstract double earnings();
}
class Manager implements Employee {
    private double weeklySalary;
    private String name;
    public Manager(String name, double s) {
        this.name = name;
        setWeeklySalary(s);
    }
    
    void setWeeklySalary(double s) {
        if (s > 0) {
          weeklySalary = s;
        } else
          weeklySalary = 0;
    }
    
    public double earnings() {
        return weeklySalary;
    }
    public String getName() {
     return name;
 }
    public String toString() {
        return "Manager: " + getName();
    }
}

class PieceWorker implements Employee {
    private double wagePerPiece;
    private int quantity;
    private String name;
    public PieceWorker(String name, double w, int q) {
        this.name = name;
        setWagePerPiece(w);
        setQuantity(q);
    }
    
    void setWagePerPiece(double w) {
        if (w > 0) 
          wagePerPiece = w;
        else
          wagePerPiece = 0;
    }
    
    void setQuantity(int q) {
        if ( q > 0)
           quantity = q;
        else
           quantity = 0;
    }
    public String getName() {
     return name;
 }    
    public double earnings() {
        return quantity * wagePerPiece;
    }
    
    public String toString() {
        return "Piece worker: " + getName();
    }
}

class HourlyWorker implements Employee {
    private double hourlyWage;
    private double hours;
    private String name;
    public HourlyWorker(String name, double w, double h) {
        this.name = name;
        setHourlyWage(w);
        setHours(h);
    }
    
    void setHourlyWage(double w) {
        if (w > 0)
            hourlyWage = w;
        else
            hourlyWage = 0;
    }
    
    void setHours(double h) {
        if ( 0 <= h && h < 168)
            hours = h;
        else
            hours = 0;
    }
    public String getName() {
     return name;
 }    
    public double earnings() {
        return hourlyWage * hours;
    }
    public String toString() {
        return "Hourly worker: " + getName();
    }
}

class CommissionWorker implements Employee {
    private double salary;
    private double commission;
    private double totalSales;
    private String name;
    public CommissionWorker(String name, 
            double salary, double commission, double totalSales) {  
        this.name = name;
        setSalary(salary);
        setCommission(commission);
        setTotalSales(totalSales);
    }
    void setSalary(double s) {
        if( s > 0)
            salary = s;
        else
            salary = 0;
    }  
    void setCommission(double c) {
        if ( c > 0)
            commission = c;
        else
            commission = 0;
    }
    void setTotalSales(double ts) {
        if (ts > 0 )
            totalSales = ts;
        else
            totalSales = 0;
    }
    public String getName() {
     return name;
 }
    public double earnings() {
        return salary + commission/100*totalSales;
    }  
    public String toString() {
        return "Commission worker:"
            + getName();
    }
}

class EmployeeTest {
    public static void main(String[] args) {
        java.util.List list = new ArrayList();
        list.add(new Manager("Bill", 800.00));
        list.add(new CommissionWorker("Newt", 400.0, 3.75, 159.99));
        list.add(new PieceWorker("Al", 2.5, 200));
        list.add(new HourlyWorker("Babara", 13.75, 40));
        list.add(new Manager("Peter", 1200.00));
        list.add(new CommissionWorker("Margret", 600.0,5.5, 200.25));
        list.add(new PieceWorker("Mark", 4.5, 333));
        list.add(new HourlyWorker("William", 31.25, 50));
    
  System.out.println("Use built-in iterator:");
  Iterator iterator = list.iterator();
  while(iterator.hasNext()) {
      Employee em = (Employee)iterator.next();
      System.out.print(em + " earns $");
   System.out.println(em.earnings());
  }
 }
}
%java EmployeeTest
Use built-in iterator:
Manager: Bill earns $800.0
Commission worker:Newt earns $405.999625
Piece worker: Al earns $500.0
Hourly worker: Babara earns $550.0
Manager: Peter earns $1200.0
Commission worker:Margret earns $611.01375
Piece worker: Mark earns $1498.5
Hourly worker: William earns $1562.5
The above example also shows a dynamic binding feature which is popular in Object-Oriented realm.
If you want to pick up a specific object from the aggregated list, you may use the following code.
while(iterator.hasNext()) {
 Employee em = (Employee)iterator.next();
 if (em instanceof Manager) {
    System.out.print(em + " earns $");
    System.out.println(em.earnings());
 }
}
The above list can also be replaced by an array and achieve the same result.

Interpreter Pattern

The Interpreter Pattern is a design pattern that defines a grammatical representation for a language along with an interpreter to interpret sentences in the language. The best example of an interpreted language is Java itself, which converts the English-written code to a byte code format, so that all the operating systems can understand it.
The UML class diagram of Interpreter design pattern can be shown as:

UML Class Diagram


In the given diagram, An abstract base class specifies the method interpret(). Each concrete subclass implements interpret() by accepting (as an argument) the current state of the language stream, and adding its contribution to the problem solving process. To make this thing clear, let’s take an example that can take the Sa, Re, Ga, Ma etc and produce the sounds for the frequencies. The “musical notes” is an Interpreted Language. The musicians read the notes, interpret them according to “Sa, Re, Ga, Ma…” or “Do, Re, Me… “, etc. For Sa, the frequency is 256 Hz, similarly, for Re, it is 288Hz and for Ga, it is 320 Hz and so on. In this case, we need these values set somewhere, so that when the system encounters any one of these messages, the related frequency can be sent to the instrument for playing the frequency. We can have it at one of the two places, one is a constants file, “token=value” and the other one being in a properties file. The properties file can give us more flexibility to change it later if required. This is how a properties file will look like: MusicalNotes.properties Sa=256
Re=288
Ga=320
Ma=352 . . . . .
After that we make a class NotesInterpreter.java to take an input from the key pressed by user and set those value as a global value. Then we make a method getFrequency for getting the frequency for the note input by the user e.g. if user enter Re, it will return 288.
NotesInterpreter.java

package bahavioral.interpreter; public class NotesInterpreter {

Private Note note;

public void getNoteFromKeys(Note note) {
Frequency freq = getFrequency(note);
sendNote(freq);
}
private Frequency getFrequency(Note note) {
return freq;
}
private void sendNote(Frequency freq) {
NotesProducer producer = new NotesProducer(); producer.playSound(freq);
}
}
Here we need to make another class in which the method produces the sound wave of the frequency it gets.

NotesProducer.java
package bahavioral.interpreter;
public class NotesProducer {
Private Frequency freq;
public NotesProducer() {
this.freq = freq;
}
public void playSound(Frequency freq) {
}
}
 The above example is the simplest way to understand the concept of interpreter pattern and know how it works. In case of Interpreter pattern we need to check for grammatical mistakes, which makes it very complex. Also,
care should be taken to make the interpreter as flexible as possible, so that the implementation can be changed at later stages without having tight coupling.