Object Oriented Programming
And S.O.L.I.D. Principles
Created by Juan Manuel Torres / @onema / onema.io
http://slides.com/onema/oop-and-solid
Object-oriented programming (OOP) is a programming paradigm that represents concepts as "objects" that have data fields (attributes that describe the object) and associated procedures known as methods [1]
What is Object Oriented Programming (OOP)?
Object-oriented programming is a style of coding that allows developers to group similar tasks into classes. [2]
What is S.O.L.I.D?
is a mnemonic acronym that stands for five basic principles of object-oriented programming and design. The principles, when applied together, intend to make it more likely that a programmer will create a system that is easy to maintain and extend over time.[3]
Who knows the difference between a class and a object?
Class Structure
class ClassName
{
// These are variables bound to the object and can
// only be accessed by the object
public $classProperty01;
public function classMethod01()
{
// Methods are class specific function.
// Objects can reference themselves using $this.
}
}
Class Name
Curly braces are required
Class Properties (variables)
Class Methods (functions)
Instantiating Classes
$myClass = new ClassName();
$myClass->classMethod01();
S
Single Responsibility Principle (SRP)
O
L
I
D
R
P
A class or module should have one, and only one, reason to change... Classes should have one responsibility—one reason to change. [4]
S
O
L
I
D
R
P
While SPR is one of the simplest OO design principles, it is one of the most abused.
WHY? Once the program works, I'm done!
Use SRP to neatly organize your application and code
________________________________________________________
S
Why do we want to use SRP?
O
L
I
D
R
P
Multipurpose classes prevents us from clearly understanding the original intention of the code.
S
Why do we want to use SRP?
O
L
I
D
R
P
Manage the complexity by organizing. Every sizable application will contain a large amount of code and complexity.
Pro Tip!
S
Why do we want to use SRP?
O
L
I
D
R
P
Easier to understand and update. With simpler classes we can directly affect complexity at any given time.
S
Why do we want to use SRP?
O
L
I
D
R
P
Better system design. Collaboration with other small classes to achieve system behavior is better than doing it all in one or few classes.
Pro Tip!
S
Why do we want to use SRP?
O
L
I
D
R
P
Easy to collaborate with other developers or teams. The likelihood of two teams working on the same part of the system is reduced; this helps prevent code and functionality conflicts.
S
Exercise 1
O
L
I
D
R
P
class Rectangle
{
public void Draw();
public void Area(double val);
}
Single or multiple responsibilities?
S
Exercise 2
O
L
I
D
R
P
interface Modem
{
public void Dial(string phone);
public void Hangup();
public void Send(char message);
public char Recv();
}
Single or multiple responsibilities?
S
Exercise 3
O
L
I
D
R
P
class Version
{
public int getMajorVersionNumber();
public int getMinorVersionNumber();
public int getPatchVersionNumber();
public int getBuildNumber();
}
Single or multiple responsibilities?
S
Exercise 4
O
L
I
D
R
P
Design a Tic-Tac-Toe game
- Two player game only
- Users can input
- Single game only
- Must display game grid
Public, protected and private properties & Methods
- Used to hold or add data to classes
- Properties have visibility (more on this later)
- Can be initialized but is not required
class Properties
class MyClass
{
public $property = "I'm a class property!";
}
$obj = new MyClass();
echo $obj->property;
Defining class Properties
Public visibility
Access contained properties & methods
- Class specific functions
- Methods have visibility (more on this later)
class Methods
class MyClass
{
public $property = "I'm a class property!";
public function setProperty($newValue)
{
$this->property = $newValue;
}
public function getProperty()
{
return $this->property;
}
}
$obj = new MyClass();
echo $obj->getProperty();
$obj->setProperty('New property value!');
echo $obj->getProperty();
Defining class Methods
Public visibility
class MyClass
{
// ...
public function __construct()
{
echo 'The class ' . __CLASS__ . ' was initiated.';
}
public function __destruct()
{
echo 'The class ' . __CLASS__ . ' was destroyed.';
}
// ...
}
$obj = new MyClass();
constructors and destructors
EOF PHP releases all resources
Inheritance
Classes can inherit properties and methods from other classes
Classes can extend the behaviour of other classes by using the "extends" keyword
class Car extends Vehicle {
public function getMakeAndModel()
{
echo $this->getMake() . ' ' . $this->getModel();
}
}
class Vehicle
{
// . . .
public function __construct($make, $model, $size = 5) {
$this->make = $make;
$this->model = $model;
$this->size = $size;
}
// . . .
public function getMake() {
return $this->make;
}
public function getModel() {
return $this->model;
}
}
Extends Keyword
Classes can overwrite public and protected properties and methods
class HondaCivic extends Car
{
// . . .
public function getMake() {
return 'Honda';
}
public function getModel() {
return 'Civic';
}
}
Overwriting
Bad Practice
class HondaCivic extends Car
{
// ...
public function getMakeAndModel($customString)
{
if (isset($customString)) {
echo $customString;
} else {
echo $this->getMake() . ' ' . $this->getModel();
}
}
// . . .
}
Violates Liskov Substitution Principle
The " L" in S.O.L.I.D. More on this later...
O
Open Close Principle
L
Classes, modules, functions should be open for extension and close for modification
Open for Extension:
This means that the behavior of the module can be extended. [5]
Closed for Modification:
The source code of such a module is inviolate. No one is allowed to make source code changes to it. [5]
C
P
I
D
S
class Vehicle {
// ...
}
class CarDriver {
public function drive($car) {
if ($car->getMake() == 'Honda') {
// do something with Honda car
} elseif ($car->getMake() == 'Toyota') {
// do something with Toyota car
} elseif ($car->getMake() == 'Ford') {
// do something with Ford car
}
}
// ...
}
class Car extends Vehicle {
// ...
}
Does not conform to the open-closed principle because it cannot be closed against new kinds of vehicles
O
L
C
P
I
D
S
abstract class Car extends Vehicle {
// ...
abstract public function drive();
}
class Honda extends Car {
// ...
public function drive() {
// implement drive
}
}
class Toyota extends Car {
// ...
public function drive() {
// implement drive
}
}
PRO TIP
Use the Strategy Pattern:
Define a contract between parent and child classes
Strategy Pattern, and other design patterns can be used to extend code without internal modifications!
O
L
C
P
I
D
S
$driver = new CarDriver();
$honda = new Honda();
$driver->drive($honda);
$toyota = new Toyota();
$driver->drive($toyota);
class CarDriver {
public function drive(Car $vehicle) {
$vehicle->drive();
}
// ...
}
CarDriver can drive any type of car without having to modify the code
O
L
C
P
I
D
S
Abstraction
Working with something we know how to use without knowing how it works internally[6]
Encapsulation
Providing users with essential information about an object for manipulation... A [person] using a Laptop only knows about its screen, keyboard and mouse. Everything else is hidden internally under the cover.
Example
class Lion extends Felidae {
private frontLeft;
private frontRight;
private bottomLeft;
private bottomRight;
public function Walk() {
$this->MovePaw($this->frontLeft);
$this->MovePaw($this->frontRight);
$this->MovePaw($this->bottomLeft);
$this->MovePaw($this->bottomRight);
}
private function movePaw(Paw $paw) {
// ...
}
// ...
}
class Felidae {
public function Walk() {
echo "Felidae walks";
}
}
We only need to know how to walk, how that is performed is not our concern!
L
Liskov Substitution Principle
S
I
Child classes should never break the parent class' type definitions [8]
If for each object o1 of type S there is an object o2 of type T such that for all programs P defined in terms of T, the behavior of P is unchanged when o1 is substituted for o2 then S is a subtype of T [9]
S
P
O
D
L
S
I
D
S
P
O
o2 (T)
o1 (S)
T
S
P
If for each object o1
there is an object o2
such that for all programs P defined in terms of T,
the behavior of P is unchanged when o1 is substituted for o2
then S is a subtype of T
of type S
of type T
L
S
I
S
P
O
D
Violation Example #1
interface bird {
public function birdSound();
public function fly();
public function display();
}
class Duck implements Bird {
public function birdSound() {
echo 'quack!';
}
public function fly() {
echo 'duck is flying!';
}
public function display() {
// display a duck
}
}
class Ostrich implements Bird {
public function birdSound() {
echo 'Ostrich noises!';
}
public function fly() {
echo "D'oh!";
}
public function display() {
// display an Ostrich
}
}
Introduces new behavior,
NON-FLYING BIRD!!!
L
S
I
S
P
O
D
Violation Example #2
class Ostrich implements Bird {
public function birdSound() {
echo 'Ostrich noises!';
}
public function fly($jetPack) {
echo "Attach jetpack to Ostrich and FLY!";
}
public function display() {
// display an Ostrich
}
}
WRONG!
L
S
I
S
P
O
D
Violation Example #2
class BirdSimulator {
private $bird;
public function setBird(Bird $bird) {
$this->bird = $bird;
}
public function main() {
if (isset($this->bird)) {
echo 'This bird says '.$this->bird->birdSound();
echo 'And this bird can also Fly '.$this->bird->fly();
}
}
}
$birdSim = new BirdSimulator();
$birdSim->setBird(new Duck());
$birdSim->main();
$birdSim->setBird(new Ostrich());
$birdSim->main();
class Ostrich implements Bird {
public function birdSound() {
echo 'Ostrich noises!';
}
public function fly($jetPack) {
echo "Attach jetpack to Ostrich and FLY!";
}
public function display() {
// display an Ostrich
}
}
What would happen here?
Declaration of Ostrich::fly() must be compatible with bird::fly()
L
S
I
D
S
P
O
If it looks like a duck
Quacks like a duck
But needs batteries
You probably have the wrong abstraction
Subtypes must be substitutable for their base types.
L
S
I
S
P
O
D
So what is the point?
The Liskov Substitution Principle (A.K.A Design by Contract) is an important feature of all programs that conform to the Open-Closed principle.
It is only when derived types are completely substitutable for their base types that functions which use those base types can be reused with impunity, and the derived types can be changed with impunity.
L
S
I
S
P
O
D
Exercise
Create an abstraction for the Bird class
Polymorphism
Describes a pattern in which classes have different behavior but share common interface [10].
Interfaces
Interfaces are a key part of polymorphism, they describe behaviors, without implementing them.
Classes implementing the interfaces must build the functionality for all the methods defined in the interface.
Example
class Lion implements Felidae {
private frontLeft;
private frontRight;
private bottomLeft;
private bottomRight;
public function Walk() {
$this->MovePaw($this->frontLeft);
$this->MovePaw($this->frontRight);
$this->MovePaw($this->bottomLeft);
$this->MovePaw($this->bottomRight);
}
private function movePaw(Paw $paw) {
// ...
}
// ...
}
interface Felidae {
public function Walk();
}
An interface is declared using the keyword interface
To implement the interface the implements operator is used
I
S
L
S
P
O
D
Interface Segregation Principle
The interface-segregation principle (ISP) states that no client should be forced to depend on methods it does not use. [11]
Classes that implement interfaces should not be forced to implement methods they do not use. [12]
I
S
L
S
P
O
D
Interface Segregation Principle
This principle deals with disadvantages of interface pollution
interface Vehicle {
public function startEngine();
public function accelerate();
public function brake();
public function lightsOn();
public function signalLeft();
public function signalRight();
public function changeGear($gear);
public function stopRadio();
public function ejectCD();
}
I
S
L
S
P
O
D
Interface Segregation Principle
Each interface should be grouped into methods that serve a different set of clients
I
S
L
S
P
O
D
Interface Segregation Principle
program to an interface not an implementation
I
S
L
S
P
O
D
Excercise
interface PlayerInterface
{
// Mount to player: weapons, potions, bags, etc
public function mountItem($item);
public function unMountItem();
// Add to player inventory
public function setItem($item);
public function getItem($itmeName);
public function hasItem($itemName);
public function removeItem($itemName);
// Health
public function damage($amount);
public function heal($amount);
public function getHealth();
// User information
public function setName($name);
public function getName();
// User stats
public function setStats($stats);
public function getStat($key);
public function isDead();
}
D
S
L
I
P
O
I
Dependency Inversion Principle
THE END
BY Juan Manuel Torres / onema.io / @onema / kinojman@gmail.comReferences
- Object-oriented programming
- Object Oriented PHP for Beginners
- SOLID
- Clean Code
- The Open-Closed Principle
- Object Oriented Programming Principles (Abstraction)
- Object Oriented Programming Principles (Encapsulation)
- Liskov Substitution & Interface Segregation Principles
- Data abstraction and Hierarchy
- Understanding and Applying Polymorphism in PHP
- Interface Segregation Principle
- The I in SOLID
References
Object Oriented Programming and SOLID concepts
By Juan Manuel Torres
Object Oriented Programming and SOLID concepts
- 2,746