Using the Memento Pattern with a File Reading Class

The memento pattern can be used to maintain the state of a property that belongs to a specific class. If you want to learn more about how to do this, start reading this tutorial! Welcome to the final installment of the series "Maintaining the State of Classes." In two parts, this series teaches you how to use the memento design pattern with PHP 5, and it accompanies the corresponding theoretical concepts with diverse hands-on examples.

Introduction

If you already read the first article of the series, then you’ll surely recall what this pattern is about. Just in case the subject doesn’t ring any bells to you, however, let me offer you a quick introduction. In short, when the memento pattern is applied, two classes are required to satisfy a well-defined model: the "originator" and the "caretaker." 

Where this pattern is used, the caretaker is capable of holding the value of one or more properties that belong to the respective originator. Nevertheless, a classic implementation of these two classes means usually that the referenced caretaker can’t directly access the properties of the originator. So how can its state be maintained? Usually the caretaker takes the originator as an input parameter, and uses all its methods to gain access to the respective properties.

All right, I think that the previous explanation should give you an accurate idea of how this pattern works. Let me now introduce the topics that I’ll be covering in this last article of the series. I’ll show you how to use the memento pattern to keep track of some properties that correspond to a file reading class. In this way we’ll construct a flexible mechanism for moving back and forth between file lines.

With the preliminaries out of our way, let’s continue exploring the capacities offered by the memento pattern. Let’s get started!

{mospagebreak title=Building an originator class}

As I stated in the beginning, implementing the memento pattern requires at least two independent classes. Therefore, the first step that I’m going to take will consist of defining one of the primary classes that comprises the structure of this pattern.

I’m referring to the originator element, which in this case is aimed at building a comprehensive file reading class. Meanwhile, the caretaker class that I plan to create will be capable of holding the value of one particular property that belongs to this file reader, in this manner implementing a basic file navigation mechanism.

Now that I’ve outlined the general structure of the originator class, you’ll want to take a look at its corresponding signature:

// define ‘FileDataReader’ class (in this case, this is the
Originator class)
class FileDataReader{
   private $filePointer;
   private $fileData;
   public function __construct(
          $dataFile=’default_data_file.txt’,$filePointer=0){
       if(!file_exists($dataFile)){
          throw new Exception(‘Invalid data file!’);
       }
       $this->setFilePointer($filePointer);
       $this->setFileData($dataFile);
   
}
   // set value for file pointer
   public function setFilePointer($filePointer){
     if(!is_int($filePointer)||$filePointer<0){
       throw new Exception(‘Invalid pointer for data file!’);
     }
     $this->filePointer=$filePointer;
   }
   // fetch value of file pointer
   public function getFilePointer(){
     return $this->filePointer;
   }
   // read data from file
   public function setFileData($dataFile){
     if(!$this->fileData=file($dataFile)){
       throw new Exception(‘Error reading from data file!’);
     }
   }
   // return file data as array
   public function getFileData(){
     return $this->fileData;
   }
   // fetch one line from data file
   public function fetchFileLine(){
     if(!$fileLine=$this->fileData[$this->filePointer]){
       throw new Exception(‘Error fetching line from file
data!’);
     }
     return $fileLine;
   }
}

As you can see, the above "FileDataReader" class is capable of performing some useful tasks, with reference to reading data from a specified text file. As to the functionality of this class, you’ll realize that it’s capable of fetching file data as an array structure, as well as retrieving one line of that file at once. Not too bad, right?

However, while I have to admit that the previous file reading class isn’t going to change your life as a PHP developer, it does show in a nutshell how to define the structure of an originator. Naturally, any class can potentially fall under that category, but in this case the "FileDataReader" class is more than enough to demonstrate the functionality of the memento pattern.

At this stage, I’m pretty certain that you grasped the logic that drives the originator class. Therefore, in the following section I’ll show you how to create the corresponding caretaker class. As I said when I explained how the caretaker class works, it will be capable of maintaining the value of a specific property.

To learn how this brand new class will be created, please click on the link shown below and keep reading.

{mospagebreak title=Defining the signature of a caretaker class}

As you might have guessed, the functionality of a caretaker class has to be strongly related to the nature of the tasks performed by the originator. Keeping in mind this basic principle, below I listed the definition for the corresponding caretaker. In a fit of inspiration, I named it "FileDataSeeker." Take a look at it, please:

// define ‘FileDataSeeker’ class (in this case, this is the
Caretaker class)
class FileDataSeeker{
   private $filePointer;
   // the constructor takes up the originator object as the only
input parameter
   public function __construct(FileDataReader $fileDataReader){
     $this->setFilePointer($fileDataReader);
   }
   public function setFilePointer(FileDataReader $fileDataReader){
     $this->filePointer=$fileDataReader->getFilePointer();
   }
   public function getFilePointer(FileDataReader $fileDataReader){
     $fileDataReader->setFilePointer($this->filePointer);
   }
}

As illustrated above, the "FileDataSeeker" class has some useful methods for handling the "filePointer" property that belongs to the respective originator class. These methods will help this caretaker class to carry out its responsibility to store the value of the property. Thus, the value can be retrieved at a later time. Pretty logical, isn’t it?

By providing the "FileDataSeeker" class with this ability, if the file reading class locates its file pointer at a non-existent place, it will be possible to move it back to a valid position via the respective caretaker. Definitely, that makes a lot of sense!

However, showing you the originator and the caretaker separately won’t give you a clear idea of how they work. Thus, in response to this issue, in the next section I’ll create a simple script, which hopefully will demonstrate the power of these two classes when they operate together.

As usual, to see how this will be achieved, go ahead and read the following section. I’ll be there, waiting for you.

{mospagebreak title=The memento design pattern in action}

As I expressed in the section that you just finished reading, one of the most educational ways to understand how the memento pattern works is by creating a practical example where the two classes are put to work together.

In this case, you’ll see how the "FileDataSeeker" class defined in a previous section is capable of maintaining the value of the "filePointer" property, which belongs to the "FileDataReader" class.

Let us assume that there is a sample text file containing the following lines of basic data:

This is the line 1 of data file.
This is the line 2 of data file.
This is the line 3 of data file.
This is the line 4 of data file.
This is the line 5 of data file.
This is the line 6 of data file.
This is the line 7 of data file.
This is the line 8 of data file.
This is the line 9 of data file.
This is the line 10 of data file.

Here is the short script that demonstrates the functionality provided by the memento pattern. Please examine the code sample below:

try{
   // example using Originator and Caretaker classes
   // instantiate new ‘FileDataReader’ object
   $fileDataReader=new FileDataReader();
   // instantiate new ‘FileDataSeeker’ object
   $fileDataSeeker=new FileDataSeeker($fileDataReader);
   // display first line of data file
   echo ‘Value for first line of data file is as follows:
‘.$fileDataReader->fetchFileLine();
           

  /*
  displays the following
  Value for first line of data file is as follows:
  This is the line 1 of data file.
  */            

  // move file pointer to last line of data file
  $fileDataReader->setFilePointer(9);
  // display last line of data file
  echo ‘Value for last line of data file is as follows:
‘.$fileDataReader->fetchFileLine();
           

  /*
  displays the following
  Value for last line of data file is as follows:
  This is the line 10 of data file.
  */           

  // store value of file pointer onto caretaker object
  $fileDataSeeker->setFilePointer($fileDataReader);
  // try to fetch an invalid line from data file
  //$fileDataReader->setFilePointer(-1);
  // trigger an error
  echo $fileDataReader->fetchFileLine();

  /*
  displays the following
  Invalid pointer for data file!
  */

  // move file pointer back to last element of data file
  // via caretaker object
  $fileDataSeeker->getFilePointer($fileDataReader);
  $fileDataReader->getFilePointer();
  echo ‘Value for last line of data file is as follows:
‘.$fileDataReader->fetchFileLine();

  /*
  displays the following:
  Value for last line of data file is as follows:
  This is the line 10 of data file.
  */
}
catch(Exception $e){
   echo $e->getMessage();
   exit();
}

With reference to the example shown above, there are some interesting things to note. First, notice how after instantiating the respective originator and caretaker objects, the first line included in the sample data file is read and displayed. So far, there is nothing unexpected, right?

However, things become a little more exciting when the file reading object is pointed to a non-existent line of the mentioned data file. This throws an exception, and consequently the execution of the script is halted. However, since the value of its "filePointer" property was previously stored by the respective "FileDataSeeker" object, it’s possible to move the pointer in question back to the last element of the data file.

This condition is clearly illustrated by the following code snippet:

// move file pointer back to last element of data file
// via caretaker object
$fileDataSeeker->getFilePointer($fileDataReader);
$fileDataReader->getFilePointer();
echo ‘Value for last line of data file is as follows:
‘.$fileDataReader->fetchFileLine();

As you can see, this is where the memento pattern comes into its own, since the value of the mentioned file pointer property is retrieved from the caretaker object. Now do you see how the state of class can be tracked with this handy pattern? I suppose you do!

As usual, feel free to incorporate your own modifications to all the classes that were shown in this tutorial. In this way you can expand your background on the memento pattern. Fun is already guaranteed!

Final thoughts

Sadly, we’ve come to the end of this series. In this pair of tutorials, I introduced the key points of how to apply the memento design pattern with PHP 5. As you saw, if you’re looking for an accessible approach for keeping track of different properties that belong to a given class, indeed this pattern could be a good choice.

See you in the next PHP tutorial!

[gp-comments width="770" linklove="off" ]

chat sex hikayeleri Ensest hikaye