One of the problems with the object-oriented examples we have used thus far is that a user can manipulate the object directly once he gets a reference to it. Even if he is supposed to use the methods provided by the module, there is nothing to stop him from accessing the object's data directly, since Perl does not specifically provide a private section for the class data. But for those who feel this lack of guaranteed privacy is an affront to the object-oriented approach, the paranoid, the sensible, etc., Perl provides several solutions. One of them is the use of closures.
Larry Wall describes closures as just anonymous subroutines with an attitude.[8] Barrie Slaymaker calls closures "inside-out objects": objects are data that have some subroutines attached to them, and closures are subroutines that have some data attached to them.
[8] Wall, L., Christianson, T., and Orwant, J., Programming Perl, 3rd ed., O'Reilly & Associates: Sebastopol, CA, 2000, p. 262.
A closure is an anonymous subroutine that has access to "my" (lexical) variables even if it is called from outside the block where the variables were defined and it seems as though those variables should no longer be in scope. The subroutine clings to the lexical variables it references. Each time the subroutine is called via its reference, a new lexical variable with the same name is created for that call. The lexical variables stay in scope until they are no longer being referenced.
Closures provide a way to encapsulate the object's data and thereby prevent the user from directly accessing the object. This can be done by defining the constructor with the object's data and an anonymous subroutine that will act as the closure. The anonymous subroutine will be the only way to set and get data for the object. Instead of blessing the data (e.g., anonymous hash into the class), the anonymous subroutine will be blessed. The pointer to the anonymous subroutine will be returned and serve as the only way to access the private data defined in the constructor. The blessed anonymous subroutine will have access to the object's data because it was declared within the same lexical scope. It encapsulates the data with the subroutine; i.e., forms a closure. As long as the anonymous subroutine refers to the object's data, the data will be accessible.
Example 14.16 will demonstrate how to use a closure to encapsulate the data for an object by following these steps.
1. | A constructor method is defined for a Student class. The constructor will define an empty anonymous hash that will be used to set properties for each new Student object, a global class variable to keep track of the number of students, and an anonymous subroutine to encapsulate the data to be assigned to and retrieved from the object. The blessing will return a pointer to the anonymous subroutine. |
2. | The instance methods will be defined for the object for setting and getting the data. Instead of getting back a pointer to the object's data, these methods will get back a pointer to the anonymous subroutine. The only way they can access the data is by calling this anonymous subroutine with the appropriate arguments. |
3. | A destructor method will be defined to display each Student object as it is being destroyed. |
Code View: use lib("lib"); 1 use Student; 2 $ptr1 = Student->new(); # Create new students $ptr2 = Student->new(); $ptr3 = Student->new(); 3 $ptr1->set("Name", "Jody Rogers"); # Set data for object $ptr1->set("Major", "Law"); $ptr2->set("Name", "Christian Dobbins"); $ptr2->set("Major", "Drama"); $ptr3->set("Name", "Tina Savage"); $ptr3->set("Major", "Art"); 4 $ptr1->display(); # Get all data for object $ptr2->display(); $ptr3->display(); 5 print "\nThe major for ", $ptr1->get("Name"), " is ", $ptr1->get("Major"), ".\n\n"; (The Output) New student created, we have 1 students. New student created, we have 2 students. New student created, we have 3 students. Student=CODE(0x225420) Name :Jody Rogers Student=CODE(0x225420) Major:Law Student=CODE(0x183192c) Name :Christian Dobbins Student=CODE(0x183192c) Major:Drama Student=CODE(0x1831a04) Name :Tina Savage Student=CODE(0x1831a04) Major:Art The major for Jody Rogers is Law. Object going out of scope: Students remain: 2 Object going out of scope: Students remain: 1 Object going out of scope: Students remain: 0 --------Try to get direct Access---------------------------------- use lib("lib"); use Student; $ptr1 = Student->new(); # Create new students $ptr2 = Student->new(); $ptr3 = Student->new(); $ptr1->("Name", "Jody Rogers"); # Direct Access Not Allowed $ptr1->set("Name", "Jody Rogers"); $ptr1->set("Major", "Law"); -------------------------------------------------- (Output) New student created, we have 1 students. New student created, we have 2 students. New student created, we have 3 students. Access type should be set or get at Student.pm line 25. ... |