Object Oriented design principles and patterns

Design principle comes before the design pattern. The design principle is a prerequisite of design pattern

Patterns:

Strategy Design Pattern

Tools we had before:

  • Inheritance ( A child class extending the parent class )
  • Polymorphism ( Polymorphism is an Inheritance and overridden methods )
  • Abstraction
  • Encapsulation ( Wrapping of variables and functions into a single class. Encapsulation is mainly used to safe data. Public, Privat, Protected )

Problems with an inheritance:
– No code reuse
– Code duplication
– No clear knowledge
– Changes in parent class affects in child class
– Compile time only / No run time support


<?php

abstract class Citizen 
{
    public function walk()
    {
        return "I am walking";
    }
    
    public function eat()
    {
        return "I am eating food";
    }
    
    public function cry()
    {
        return "I am crying";
    }
    
    abstract function show();
}

class Human extends Citizen
{
    public function show()
    {
        return "I look like a Human";
    }
}

class Chimpanzee extends Citizen
{
    public function show()
    {
        return "I look like a Chimpanzee";
    }
}

class Alien extends Citizen
{
    public function show()
    {
        return "I look like an Alien";
    }
    
    public function eat()
    {
        return "I am eating ViaSunlight";
    }
    
    public function cry()
    {
        return "I dont' cry";
    }
}

class Robot extends Citizen
{
    public function show()
    {
        return "I look like a Robot";
    }
    
    public function eat()
    {
        return "I do not eat";
    }
    
    public function cry()
    {
        return "I do not cry";
    }
}

$instance = new Alien();
echo $instance->cry();

Problems with an interface:
– No code reuse
– Maintenance nightmare
– Compile time only / No run time support


<?php

abstract class Citizen 
{
    public function walk()
    {
        return "I am walking";
    }
    
    abstract function show();
}

interface Eater
{
    public function eat();
}

interface Cryer
{
    public function cry();
}

class Human extends Citizen implements Eater, Cryer
{
    public function show()
    {
        return "I look like a Human";
    }
    
    public function eat()
    {
        return "I am eating food";
    }
    
    public function cry()
    {
        return "I am crying";
    }
    
}

class Chimpanzee extends Citizen implements Eater, Cryer
{
    public function show()
    {
        return "I look like a Chimpanzee";
    }
    
    public function eat()
    {
        return "I am eating food";
    }
    
    public function cry()
    {
        return "I am crying";
    }
}

class Alien extends Citizen implements Eater
{
    public function show()
    {
        return "I look like an Alien";
    }
    
    public function eat()
    {
        return "I am eating ViaSunlight";
    }
    
}

class Robot extends Citizen
{
    public function show()
    {
        return "I look like a Robot";
    }
   
}

$instance = new Alien();
echo $instance->eat();

Problem with a construct:
– Compile time only / No run time support


<?php

abstract class Citizen 
{
    private $eater;
    private $cryer;
    
    public function __construct(Eater $eater, Cryer $cryer)
    {
        $this->eater = $eater;
        $this->cryter = $cryer;
    }
    
    public function walk()
    {
        return "I am walking";
    }
    
    public function goEat()
    {
        return $this->eater->eat();
    }
    
    public function goCry()
    {
        return $this->cryer->cry();
    }
    
    abstract function show();
}

interface Eater
{
    public function eat();
}

interface Cryer
{
    public function cry();
}

// Encapsulate what vaires
class CanEat implements Eater
{
    public function eat()
    {
        return "I am eating food";
    }
}

class CantEat implements Eater
{
    public function eat()
    {
        return "I do not eat";
    }
}

class EatViaSunlight implements Eater
{
    public function eat()
    {
        return "I am eating ViaSunlight";
    }
}

class CanCry implements Cryer
{
    public function cry()
    {
        return "I am crying";
    }
}


class CantCry implements Cryer
{
    public function cry()
    {
        return "I do not cry";
    }
}

class Human extends Citizen
{
    public function show()
    {
        return "I look like a Human";
    }
}

class Chimpanzee extends Citizen
{
    public function show()
    {
        return "I look like a Chimpanzee";
    }
}

class Alien extends Citizen
{
    public function show()
    {
        return "I look like an Alien";
    }
   
}

class Robot extends Citizen
{
    public function show()
    {
        return "I look like a Robot";
    }
    
}

$instance = new Alien(new EatViaSunlight(), new CantCry());
echo $instance->goEat().PHP_EOL;
$instance->eater = new CanEat();
echo $instance->goEat();

Tools we have added:

Principles:
Encapsulate what varies ( কোডের যেই অংশ পরিবত্তনশীল সেই অংশ অপরিবত্তনীয় কোড থেকে পৃথক করে নিয়ে আসা )
Encapsulate varies এর প্রথম ধাপ হচ্ছে behavior গুলোকেই class হিসেবে declare করতে হবে।
Composition over inheritance
Code to an interface, not to an implementation.
Open for extension, close for modification

Final Solution


<?php

// Open for extenstion, close for modification.
abstract class Citizen
{
    // Composition over inheritance.
    private $eater;
    private $cryer;
    
    // Code to an interface, not to an implementation
    public function setEater(Eater $eater)
    {
        $this->eater = $eater;
    }
    
    public function setCryer(Cryer $cryer)
    {
        $this->cryer = $cryer;
    }
    
    public function walk()
    {
        return "I am walking.";
    }
    
    public function goEat()
    {
        return $this->eater->eat();
    }
    
    public function goCry()
    {
        return $this->cryer->cry();
    }
    
    abstract function show();
}

interface Eater
{
    public function eat();
}

interface Cryer
{
    public function cry();
}

// Encapsulate what varies
class CanEat implements Eater
{
    public function eat()
    {
        return "I am eating.";
    }
}

class CantEat implements Eater
{
    public function eat()
    {
        return "I do not eat.";
    }
}

class EatsViaSunlight implements Eater
{
    public function eat()
    {
        return "I am eating via sunlight.";
    }
}

class CanCry implements Cryer
{
    public function cry()
    {
        return "I am crying.";
    }
}

class CantCry implements Cryer
{
    public function cry()
    {
        return "I do not cry.";
    }
}

class Weep implements Cryer
{
    public function cry()
    {
        return "I am weeping.";
    }
}

class Human extends Citizen
{
    public function show()
    {
        return "I look like a human.";
    }
}

class Chimpanzee extends Citizen
{
    public function show()
    {
        return "I look like a chimp.";
    }
}

class Alien extends Citizen
{
    public function show()
    {
        return "I look like an alien.";
    }
}

class Robot extends Citizen
{
    public function show()
    {
        return "I look like a Robot.";
    }
}

$alien = new Alien();

$alien->setEater(new EatsViaSunlight());

echo $alien->goEat() . PHP_EOL;

$alien->setEater(new CanEat());

echo $alien->goEat();

Recursive Function

A recursive function is a function that calls itself. If the function keeps calling itself, how does it know when to stop? You set up a condition.

<?php
class Recursion{
	function recursive($num){
		echo $num,"<br/>";
		if(isset($num) && $num < 10){
			return $this->recursive($num + 1);
		}
	}
}
$obj = new Recursion;
$obj->recursive(1);

Traits in PHP

Basically multiple inheritance does not supported by PHP. One class can only extend or inherit from one other class. But there are many cases when you want to extend more than one classes for code reusability. To overcome this problem, as of version 5.4, PHP introduced a new feature of code reuse named trait.

So what are Traits?. Traits are a mechanism for code reuse. A Trait is simply a group of methods that you want include within another class. A Trait, like an abstract class, but It is not allowed to instantiate a trait on its own.

/* mobile.php */

<?php

class Mobile{

	function model(){

		echo "Samsung Galexy 5 <br/>";
	}

}


/* charger.php */

<?php

trait Charger{

	function battery(){

		echo "2500 MP Battery <br/>";
	}

	function power(){

		echo "The Power of Battery 5.5 </br>";
	}


}


/* projector.php */

<?php

trait Projector{

	function range(){

		echo "Projector range 5 meter <br>";
	}

	function power(){

		echo "The Power of Projector Range 2.5<br/>";
	}

	
}


/* body.php */

<?php

trait Body{

	function display(){

		echo "Display 5.5 inc <br/>";
	}

	public $name = "Smart Phone";

	abstract function tabu();
}


/* glass.php */

<?php

include_once('body.php');

trait Glass{

	use Body;

	/*function display(){

		echo "Cornic Gorila Glass <br>";
	}*/
}


/* index.php */

<?php

include_once('mobile.php');
include_once('charger.php');
include_once('projector.php');
include_once('glass.php');


class Samsung extends Mobile{

	use Charger, Projector, Glass{

		Charger::power insteadof Projector;
		Projector::power as Ppower;
	}

	/*function display(){

		echo "This is from index";
	}*/

	function tabu(){

	}
}

$obj = new Samsung;
$obj->model();
$obj->battery();
$obj->range();
$obj->power();
$obj->Ppower();
$obj->display();
echo $obj->name;


Namespace

Normally PHP does not allowed to use same multiple class name or method. So what you do on that situation. You can use Namespace. Namespace just like a virtual directory. You can use same multiple class name or method without a name collision.


/* first.php */
<?php

class A{

	function __construct(){

		echo "I am at global space </br>";
	}
}

/* second.php */
<?php

namespace second;

class A{

	function __construct(){

		echo "I am at second space <br/>";
	}
}


/* index.php */
<?php

include "first.php";
include "second.php";

use second\A;

//$obj = new second\A;	// qualified class name

$obj = new A;		// unqualified class name

$obj = new \A;		// fully qualified class name




Late Static Bindings

The self keyword does not follow the same rules of inheritance. self always resolves to the class in which it is used. This means that if you make a method in a parent class and call it from a child class, self will not reference the child as you might expect.


<?php

class Php{

	public static function framework(){

		echo static::getClass()."<br/>";

	}

	public static function getClass(){

		return __CLASS__;
	}
}

class ChildPhp extends Php{

	public static function getClass(){

		return __CLASS__;
	}
}


$php = new php;
$php->framework();


$childphp = new ChildPhp;
$childphp->framework();

Constant

A constant is declared with the const keyword followed by a name (is not prefixed with a dollar sign like properties).
Syntax: const CONSTANT_NAME
The main difference between properties and constants is that the constant value cannot be changed once it is set.


<?php

/**
 * Area	= π r2
 */

// Procedural way constant define
// define("CONSTANT_NAME", 'value');

class Circle {

	const PI = 3.1415;

	public function area($radius){

		return $radius * $radius * self::PI;
	}
	
}

$circle = new Circle;
echo $circle->area(5);

Static in PHP

Static properties and methods in php can directly accessible without creating object of class. You can declare static property and method using static keyword.

<?php

class User{

	public static $name;

	static function getName(){

		self::$name = "Ataur Rahman";
	}
}

User::getName();
echo User::$name;

PHP Inheritance

It allows you to create a new class that reuses the properties and methods from an existing class. A class that inherits from another class is called subclass (also a child class).


<?php

class Fruits{

	public $name;

	public function setName($name){
		$this->name = $name;
	}
}

class Apple extends Fruits{

	function juice(){
		echo "Juice <br/>";
	}
}


class Mango extends Fruits{

	
}

$apple = new Apple();
$apple->juice();
$apple->setName("My Apple");
echo $apple->name;

echo "<br/>";

$mango = new Mango();
$mango->setName("My Mango");
echo $mango->name;

Type Hinting

You can specify what type of data expected in a function declaration. It could be Array type, int type, object type data.

<?php

class Book{

	public $price;
	public $authors;

	function getPrice(int $price){

		$this->price = $price;

	}

	function Authors(array $name){

		$this->authors = $name;

	}
}

$book = new Book;
$book->getPrice(100);
echo $book->price;

echo "<br/>";

$book->Authors(['Araf','Jahir']);
print_r($book->authors);

Abstract Class

An abstract class cannot be instantiated. In other words, it is not allowed to create a new instance of an abstract class. An abstract class can contain properties and methods.

<?php

abstract class Student{

	public $name;
	public $age;

	public function details(){

		return "My name is ".$this->name.". I am ".$this->age." years old <br/>";
	}

	abstract public function book();
}


class Boy extends Student{

	function describe(){

		return	parent::details()." and I am a college student <br/>";
	}

	public function book(){

		return "I like to read story book";
	}
	
}

$boy = new Boy;
$boy->name = "Faruk";
$boy->age = 18;
echo $boy->describe();
echo $boy->book();