solid [Docs]

User Tools

Site Tools


solid

SOLID

Single responsability

Definition: A class should have one and only one reason to change, meaning that a class should have only one job. Ex: A class that calculates area of a shape also manages authentication, connection to db and rendering. WRONG! Problems of GOD class:

  • Uses a lot of dependencies
  • Contains different types of logic
  • Nothing is decoupled
  • It's no opened to extension Solutions:
  • Use layers to separate logics
  • Proper naming
  • DI

Open-Close

Definition: Objects or entities should be open for extension, but closed for modification.

For PHP:

  • Classes should allow the creation of new properties or methods
  • Classes should not allow modification of current properties or methods.
  • Classes should have rich documented interfaces or prototypes.
public function sum() { 
	foreach ($this->shapes as  $shape) { 
		if(is_a($shape, 'Square')){ 
			$area[] = pow($shape->length, 2); 
		} elseif (is_a($shape, 'Circle')){ 
			$area[] = pi() * pow($shape->radius, 2); 
		}
	 } 
	return array_sum($area); 
}

=> Create an interface for all different shapes and make the method "area" compulsory

Liskov Substitution

Definition: Objects in a program should be replaceable with instances of their subtypes without altering the correctness of that program.

  • If we have a Tesla is a subtype of a Car, then I should be able to drive either a Car or a Tesla the same way.
  • Classes should depend on non-concrete class when possible, like abstract or interfaces
  • Classes extensions must use the same prototype as their parents.
  • When implementing an Interface there is a contract in the input but should be a contract on the output to. (Also exceptions) Problem: If we use the interface we act expecting some output. Code Smell: instanceof Solution: Doc Blocks and return type hinting

Interface segregation

Definition: A client should never be forced to implement an interface that it doesn't use or clients shouldn't be forced to depend on methods they do not use.

  • Many client-specific interfaces are better than one general-purpose interface Solution:
  • Use dependencies
  • Split the class into => interfaces + abstractions
  • Implement abstractions in a way that don't knoe about other classses' behavior
interface WorkerInterface {
	public function work(); 
	public function sleep();
}
class Worker implements WorkerInterface { 
	public function work(){} 
	public function sleep(){}
}
class Android implements WorkerInterface {
	public function work(){} 
	public function sleep(){ return null; }
}
class Captain {
        public function manage (WorkerInterface $worker) {
		$worker->work();
		$worker->sleep();
	}
}

=>

interface WorkableInterface {
	public function work(); 
}
interface SleepableInterface {
	public function sleep();
}
class Worker implements WorkableInterface, SleepableInterface{ 
	public function work(){} 
	public function sleep(){}
}
class Android implements WorkableInterface {
	public function work(){} 
}
class Captain {
	 public function manage (¿?¿?¿? $worker) {
		$worker->work();
		$worker->sleep();
	}
}

=>

interface ManageableInterface {
	public function beManaged(); 
}
interface WorkableInterface {
	public function work(); 
}
interface SleepableInterface {
	public function sleep();
}
class Worker implements WorkableInterface, SleepableInterface, ManageableInterface{ 
	public function work(){} 
	public function sleep(){}
	public function beManaged(){
		$this->work();
		$this->sleep(); 
	}	
}
class Android implements WorkableInterface, ManageableInterface {
	public function work(){} 
	public function beManaged(){
		$this->work();
	}
}
class Captain {
	 public function manage (ManageableInterface $worker) {
		$worker->beManaged();
	}
}

Dependency inversion

Definition:

  • High-level modules should not depend on low-level modules. Both should depend on abstractions. A Module object should not depend on a Child object, but rather on ChildInterface or AbstractChild.
  • Abstractions should not depend upon details. Details should depend upon abstractions. And a Child object should receive calls not from a Moduleclass but from a ModuleInterface Put simply, this means our dependencies should be interfaces/contracts or abstract classes rather than concrete implementations.

    class PasswordReminder {
      private $dbConnection;
     
      public function __construct(MySQLConnection $dbConnection) {
          $this->dbConnection = $dbConnection;
      }
    }

    PasswordReminder => hig level MySQLConnection => low level =>

interface DBConnectionInterface {
    public function connect();
}
class MySQLConnection implements DBConnectionInterface {
    public function connect() {
        return "Database connection";
    }
}
 
class PasswordReminder {
    private $dbConnection;
 
    public function __construct(DBConnectionInterface $dbConnection) {
        $this->dbConnection = $dbConnection;
    }
}

https://medium.com/backticks-tildes/the-s-o-l-i-d-principles-in-pictures-b34ce2f1e898

solid.txt · Last modified: 2021/05/05 10:06 by superuser