- Why use OOP over procedural programming, as I have been doing?
- Encapsulation and modularity
- Basic class design
Why OOP?- A Look at Encapsulation and Modularity
Object-Oriented Programming is a very different paradigm than procedural programming, revolving around abstract modeling of Objects and their interactions rather than simply throwing code line-by-line at a solution. It allows for a cleaner, more modular, and better encapsulated solution. Let's start by examining some procedural PHP:
$people = array(
"John Doe" => array("John", "Doe", "Male", 45),
"Macosxnerd101" => array("Mac","osxnerd101","Male",17)
);
foreach($people as $person){
foreach($person as $attribute){
echo $attribute." ";
}
echo "\n<br>\n\n";
}
As we can see, we have a multi-dimmensional array modeling a list of people. Great, we can go through with nested foreach loops in O(n^2) time (O(kn) time if you want to do more than the basic analysis) and print out the list, one person per line. But let's examine some of the limitations and down-sides to this approach. First, we don't have any encapsulation here. This means that any element in the 2D array can access any other element, and it is harder to keep the elements in correpsonding arrays grouped together. This is very poor practice, as you the programmer should provide no avenues for accidents resulting in data corruption to occur.
In terms of modularity, we are lacking here as well. First, we really should be using a function to format the String a little better. We really don't know (yes by looking, but not programatically) which attributes are which. Yes, we could key them making an associative array, but this still leaves us with poor encapsulation. In addition, what if we wanted to create more person arrays to be stored in people? We can still design a function fill a new array with the appropriate attributes and push it onto $people, but we are getting down into the area of getting it working vs. getting it working right.
Now, let's examine how OOP can give us a better design, starting with our class. I've commented the individual elements of the class, with a look at the overall design after we finish designing our class.
//here we have a class Person
//which abstractly models a Person
class Person{
//these are instance variables
//which are associated with each
//instance of the class
private $firstName;
private $lastName;
private $gender;
private $age;
//here, we define the constructor, which
//initializes our instance variables
//the developer can either pass in their own values
//or use the pre-initialized values
//while I did not do any validation here, you certaintly have
//more power to validate the types and values being passed
//rather than relying on the user to input something valid
public function __construct($firstName = "John", $lastName = "Doe", $gender = "Male", $age = 40){
$this->firstName = $firstName;
$this->lastName = $lastName;
$this->gender = $gender;
$this->age = age;
}
//these are our accessor and mutator methods
//as our instance variables are private, we must use
//accessor and mutator methods to grant appropriate access
//or we can choose not to give the desired read or write
//access. this is the power of encapsulation
public function setFirstName($firstName){$this->firstName = $firstName;}
public function getFirstName(){return $this->firstName;}
public function setLastName($lastName){$this->lastName = $lastName;}
public function getLastName(){return $this->lastName;}
public function setGender($gender){$this->gender = $gender;}
public function getGender(){return $this->gender;}
public function setAge($age){$this->age = $age;}
public function getAge(){return $this->age;}
//this is another magic function that
//determines how Person objects react
//when converted to Strings
//It is a good practice to output something
//either very parser friendly for reading
//in the data from a File or visually
//friendly for users, so that it saves
//you some work down the road
public function __toString(){
return $this->lastName.", ".$this->firstName.
"\nGender: ".$this->gender."\nAge: ".$this->age;
}
}
Now that we have our class, let's examine some components of the design. Probably the most important concept here is encapsulation. Obviously, our instance variables are private. This means that we only need to know the results when we access or mutate them through the appropriate functions, but not how the code mutates them. In addition, you have more closely related attributes, so it is nearly impossible to accidentally mismatch attributes from two Persons, unlike the 2D and parallel arrays models.
So now that we have designed our class, let's refactor our original example using classes and Objects instead.
$people = array();
//create a John Doe and insert it into the array
$people[] = new Person();
//create a new Person Jane Smith, a female
//however, I don't want to adjust the age
$people[] = new Person("Jane", "Smith", "Female");
foreach($people as $x){
//__toString() is invoked here
//so there is no need to manually format
//the Object
echo $x."<br>\n";
}
As you can see, we still have two Persons, but it is much easier to insert new Persons into the $people array because of the constructor and encapsulation. This also allows for a more modular and reusable Person class, rather than reinventing the wheel for each script. In addition, the __toString() function allows for easy, predefined formatting. So now we are down to O(n) vs. O(n^2) (or even O(kn)).
This post has been edited by macosxnerd101: 04 July 2010 - 10:49 AM








MultiQuote






|