Hiding a workload generator's implemenation

Workload generators are basic classes in the target language where the methods of the class represent the actions that the workload generator can perform, and the parameters are the workloads associated with the actions. In most cases, you can just write the class as you normally would write a class. For example, the code below shows the header file for a workload generator that prints a single message when its sayGreeting() action is invoked.

 
// GreetingWorker.h 
class GreetingWorker { 
  void sayGreeting (const std::string & name); 
}; 

// GreetingWorker.cpp 
void GreetingWorker::sayGreeting (const std::string & name) { 
  std::cout << "Hello, " << name << std::endl; 
} 

This workload generator can be easily imported into the model, and compile correctly when added to a component. There are cases, however, where your workload may use other dependencies in its implementation, such as invoking a function/method in an imported library. In this scenario, the standard way of writing a workload generator (as illustrated) above will not work. This is because the component will need to understand those dependencies as well.

Although we do not capture this information in the model because it can make the model more cumbersome, it is possible implement a workload generator that requires additional dependencies. It requires using a technique called implementation hiding where the workload generator is aware of its implementation, but the component that uses the workload generator is not exposed to the implementation.

Using the example above, we can implement implementation hiding as follows:

 
// GreetingWorker.h 
class GreetingWorkerImpl;

class GreetingWorker { 
public:
  GreetingWorker (void);
  void sayGreeting (const std::string & name); 

private:
  std::auto_ptr  impl_;
}; 

// GreetingWorker.cpp 
#include "GreetingWorkerImpl.h"

GreetingWorker::GreetingWorker (void) 
: impl_ (new GreetingWorkerImpl ()) {

}

void GreetingWorker::sayGreeting (const std::string & name) { 
  this->impl_->sayGreeting (name);
} 

// GreetingWorkerImpl.h
class GreetingWorkerImpl {
  void sayGreeting (const std::string & name); 
};

// GreetingWorkerImpl.cpp
void GreetingWorkerImpl::sayGreeting (const std::string & name) {
  std::cout << "Hello, " << name << std::endl;   
}

As shown in the code above, there is an implementation class (i.e., GreetingWorkerImpl) that implements the workload generator's actions (similar to the first example). Then there is a workload generator class (i.e., GreetingWorker) class that uses the implementation. The workload generator class is modeled and implemented in the component. Now, when the component is compiled, it will not need to know the dependencies associated with the workload generator's implementation.