Приглашаем посетить
Спорт (sport.niv.ru)

Hack 72. Link Up Two Modules with an Adapter

Previous
Table of Contents
Next

Hack 72. Link Up Two Modules with an Adapter

Hack 72. Link Up Two Modules with an Adapter Hack 72. Link Up Two Modules with an Adapter

Use an adapter class to transfer data between two modules when you don't want to change the API of either module.

Sometimes you have to get data from two objects, each of which uses a different data format. Changing one or both objects just isn't an option because you'll have to make all sorts of other changes in the rest of your code. One solution to this problem is to use an adapter class. An adapter is a class that understands both sides of the data-transfer fence and adapts one object to talk to another.

The adapter demonstrated in this hack adapts data from a mock database object into data usable by a text-graphing engine.

Figure 7-6 shows the RecordGraphAdapter sitting between the TextGraph on the left and the RecordList on the right. The TextGraph object very nicely specifies the format it expects for data using an abstract class called TextGraphDataSource. The RecordList is a container class that has a list of Records, where each Record contains a name, age, and salary.

Figure 7-6. The adapter sitting between the graph and the data
Hack 72. Link Up Two Modules with an Adapter


For this example, I want a graph of the salaries. The adapter's job is to take data from the RecordList and convert it into a form suitable for the TextGraph by turning the data into a TextGraphDataSource object.

7.7.1. The Code

Save the code in Example 7-6 as adapter.php.

Example 7-6. An adapter example using a text graph
	<?php
	abstract class TextGraphDataSource
	{
	  abstract function getCount();
	  abstract function getName( $row );
	  abstract function getValue( $row );
	}

	class TextGraph
	{
	  private $data;
	  private $dmin;
	  private $dmax;
	  public function TextGraph( $data )
	  {
	    $this->data = $data;
	  }

	  protected function calculateMinMax()
	  {
		$this->dmin = 100000;
		$this->dmax = -100000;
		for( $r = 0; $r < $this->data->getCount(); $r++ )
		{
		  $v = $this->data->getValue( $r );
		  if ( $v < $this->dmin ) { $this->dmin = $v; }
		  if ( $v > $this->dmax ) { $this->dmax = $v; }
		}
	  }

	  public function render()
	  {
	    $this->calculateMinMax();
		$ratio = 40 / ( $this->dmax - $this->dmin );
		for( $r = 0; $r < $this->data->getCount(); $r++ )
		{
		  $n = $this->data->getName( $r );
		  $v = $this->data->getValue( $r );
		  $s = ( $v - $this->dmin ) * $ratio;
		  echo( sprintf( "%10s : ", $n ) );
		  for( $st = 0; $st < $s; $st++ ) { echo("*"); }
		  echo( "\n" );
		}
	  }
	}
	
	class Record
	{
	  public $name;
	  public $age;
	  public $salary;
	  public function Record( $name, $age, $salary )
	  {
	    $this->name = $name;
		$this->age = $age;
		$this->salary = $salary;
	  }
	}
	
	class RecordList
	{
	  private $records = array();
	  
	  public function RecordList()
	  {
		$this->records []= new Record( "Jimmy", 23, 26000 );
		$this->records []= new Record( "Betty", 24, 29000 );
		$this->records []= new Record( "Sally", 28, 42000 );
		$this->records []= new Record( "Jerry", 28, 120000 );
		$this->records []= new Record( "George", 43, 204000 );
	  }
	  
	  public function getRecords()
	  {
		return $this->records;
	  }
	}

	class RecordGraphAdapter extends TextGraphDataSource
	{
	  private $records;

	  public function RecordGraphAdapter( $rl )
	  {
	    $this->records = $rl->getRecords();
	  }
	  public function getCount( )
	  {
	    return count( $this->records );
	  }
	  public function getName( $row )
	  {
	    return $this->records[ $row ]->name;
	  }
	  public function getValue( $row )
	  {
		return $this->records[ $row ]->salary;
	  }
	}
		
	$rl = new RecordList();

	$ga = new RecordGraphAdapter( $rl );

	$tg = new TextGraph( $ga );
	$tg->render();
	?>

The top portion of the file is dedicated to the graph. This portion defines the TextGraphDataSource abstract class as well as the TextGraph class. TextGraph uses a TextGraphDataSource to reference the data. The middle section defines the Record and the RecordList (which holds the data to be graphed). The third section defines the RecordGraphAdapter, which adapts the RecordList to a source usable by the graph.

The text code at the bottom first creates a RecordList and then creates the adapter and the TextGraph, with a reference to the adapter. The graph plots the data by reading the data from the adapter.

7.7.2. Running the Hack

You run this hack on the command line using the PHP command-line interpreter:

	% php adapter.php
		 Jimmy :
		 Betty : *
		 Sally : ****
		 Jerry : **********************
		George : ****************************************

The bottom end of the scale is Jimmy, and the top end is George. The graph auto-scales so that Jimmy is shown with no stars (the minimum), and George with 40 stars (the maximum). Good going, George! More importantly, of course, this code handled the data conversion with no problem, and without messing around with the internals of the Record class.

Use an adapter any time you have two APIs that need to work together, and where changing either of those APIs is not an option.


Previous
Table of Contents
Next