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();