command design pattern in java with real world example

The Command Pattern is a behavioral design pattern in which an object is used to encapsulate all information needed to perform an action or trigger an event at a later time. The command object encapsulates a request by binding together a set of actions on a specific receiver. To achieve this, it packages the actions and the receiver up into an object that exposes just one method, execute(). When called, execute() causes the actions to be invoked on the receiver. From the outside, no other objects really know what actions get performed on what receiver they just know that if they call the execute() method, their request will be serviced.

A command pattern basically have below four components

Command – We can think of this as the interface and its implementations that are being called by the invoker.

Receiver – This is the object that actually knows how commands are executed. Think of this as an object that is being passed to the command and then used in the interface method.

Invoker – It invokes the commands by calling their interface method. As we mentioned earlier, it might not even know what commands are being invoked.

Client – It more or less guides which commands are executed when by using the invoker.

Below is the generic diagram for this pattern


diagram borrowed from book “Head First Design Patterns”

Lets say we have scenario where we need to query different databases like a oracle db and hsql db to get different information. We want to completely encapsulate this so the clients can choose which ever database they want to choose and also the query information is completely embedded into the command object and clients just have to choose the right command object and the rest will be taken care by the command object which is also composed with a receiver which in this case is oracle or hsql database.

Lets code the four components of the command pattern

Receivers

We have two receivers now one is oracle and the other is hsql. Dbtype is the receiver interface which will be implemented by our concrete classes oracle and hsql which is composed of the jdbc spring template. The oracle jdbc template have been configured in the spring context file as below and similarly hsql template is also configured the same way.


<bean id="oracleJdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<constructor-arg ref="dataSource" />
</bean>

<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<property name="driverClassName" value="${jdbc.driverClassName}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
<property name="initialSize" value="2"></property>
<property name="maxIdle" value="3"></property>
<property name="minIdle" value="2"></property>
<property name="accessToUnderlyingConnectionAllowed" value="true"></property>
</bean>


public interface DbType {

public <T extends Model> List<T> query(String query, Object[] parametrs, RowMapper<T> rowMapper);

}


import java.sql.Connection;
import java.util.List;
import org.apache.commons.dbcp.DelegatingConnection;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.jdbc.core.namedparam.SqlParameterSource;
import org.springframework.stereotype.Component;
import oracle.jdbc.driver.OracleConnection;

@Component("oracle")
public class Oracle implements DbType {

@Autowired
@Qualifier("oracleJdbcTemplate")
private JdbcTemplate jdbcTemplateOracle;

public JdbcTemplate getJdbcTemplate() {
return jdbcTemplateOracle;
}

public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
this.jdbcTemplateOracle = jdbcTemplate;
}

@Override
public <T extends Model> List<T> query(String query, Object[] parameters, RowMapper<T> rowMapper) {
Oracle.logger.info("Running the select query " + query);
return this.getJdbcTemplate().query(query, parameters, rowMapper);
}

}


import java.sql.Connection;
import java.util.List;
import org.apache.commons.dbcp.DelegatingConnection;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.jdbc.core.namedparam.SqlParameterSource;
import org.springframework.stereotype.Component;
import oracle.jdbc.driver.OracleConnection;

@Component("hsql")
public class Hsql implements DbType {

@Autowired
@Qualifier("hsqlJdbcTemplate")
private JdbcTemplate jdbcTemplateHsql;

public JdbcTemplate getJdbcTemplate() {
return jdbcTemplateHsql;
}

public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
this.jdbcTemplateHsql = jdbcTemplate;
}

@Override
public <T extends Model> List<T> query(String query, Object[] parameters, RowMapper<T> rowMapper) {
return this.getJdbcTemplate().query(query, parameters, rowMapper);
}

}

Command

QueryCommand is the command interface which will be implemented by all the commands . For this explanation we have two command object RawTableCommand and RawAggTableCommand which will implement the QueryCommand interface. The command object is composed of the receivers and the query action will be called on the receiver object.


import java.util.List;

public abstract class QueryCommand {

public <T extends Model> List<T> execute(Object[] parameters) {
throw new InvalidOperationException("Operation not supported for this object");
}

}


public class RawTableCommand extends QueryCommand {

private DbType dbtype;

public RawTableCommand(DbType dbtype) {
super();
this.dbtype = dbtype;
}

@SuppressWarnings("unchecked")
@Override
public List<RawMetric> execute(Object[] parameters) {
ConfigFile scriptFile = new ConfigFile(Constants.QUERY_RAWTABLE, FileType.script);
String script = scriptFile.getFileContent();
return dbtype.query(script, parameters, new RawMetricMapper());
}

}


public class RawAggTableCommand extends QueryCommand {

private DbType dbtype;

public RawAggTableCommand(DbType dbtype) {
super();
this.dbtype = dbtype;
}

@SuppressWarnings("unchecked")
@Override
public List<RawMetric> execute(Object[] parameters) {
ConfigFile scriptFile = new ConfigFile(Constants.QUERY_RAWTABLE, FileType.script);
String script = scriptFile.getFileContent();
return dbtype.query(script, parameters, new RawMetricMapper());
}

}

Invoker

The invoker invokes the commands by calling their interface method and it might not even know what commands are being invoked. QueryInvoker is composed of the query command and once the clients calls the execute method the QueryInvoker delegates the call to the composed command object.


public class QueryInvoker {

private QueryCommand queryCommand;

public QueryInvoker(QueryCommand queryCommand) {
super();
this.queryCommand = queryCommand;
}

public QueryCommand getQueryCommand() {
return queryCommand;
}

public void setQueryCommand(QueryCommand queryCommand) {
this.queryCommand = queryCommand;
}

public <T extends Model> List<T> execute(Object[] parameters) {
return queryCommand.execute(parameters);
}

}

Below the client class which will call the required action using the QueryInvoker which takes a command object which in turn takes a receiver which can be of dbtype.


public class Test {

public static void main(String[] args) {

QueryInvoker queryInvokerOracle = new QueryInvoker(new RawTableCommand(new Oracle()));

List<RawMetric> listOfMetric = queryInvokerOracle.execute(new Object[] { "parameter1", "parameter2" });

// Now the same command can be used with hsql database

QueryInvoker queryInvokerHsql = new QueryInvoker(new RawTableCommand(new Hsql()));

List<RawMetric> listOfMetric2 = queryInvokerHsql.execute(new Object[] { "parameter1", "parameter2" });

}

}

3 thoughts on “command design pattern in java with real world example”

Comments are closed.