
Principles SOLID adalah standar pemrograman yang harus dipahami semua pengembang dengan baik untuk menghindari penciptaan arsitektur yang buruk. Standar ini banyak digunakan dalam OOP. Jika diterapkan dengan benar, itu membuat kode lebih dapat diperluas, logis, dan mudah dibaca. Ketika pengembang membuat aplikasi, dipandu oleh arsitektur yang buruk, kode tersebut ternyata tidak fleksibel, bahkan perubahan kecil di dalamnya dapat menyebabkan bug. Karena itu, Anda harus mengikuti prinsip-prinsip SOLID.
Diperlukan waktu untuk menguasainya, tetapi jika Anda menulis kode sesuai dengan prinsip-prinsip ini, kualitasnya akan meningkat, dan Anda akan menguasai penciptaan arsitektur perangkat lunak yang baik.
Untuk memahami prinsip-prinsip SOLID, Anda perlu memahami cara menggunakan antarmuka dengan jelas. Jika Anda tidak memiliki pemahaman seperti itu, maka baca
dokumentasi terlebih dahulu.
Saya akan menjelaskan SOLID dengan cara paling sederhana, sehingga lebih mudah bagi pemula untuk mengetahuinya. Kami akan mempertimbangkan prinsip satu per satu.
Prinsip Tanggung Jawab Tunggal
Hanya ada satu alasan yang menyebabkan perubahan kelas.
Satu kelas harus menyelesaikan hanya satu masalah. Mungkin ada beberapa metode, tetapi mereka hanya boleh digunakan untuk menyelesaikan masalah umum. Semua metode dan properti harus melayani satu tujuan. Jika suatu kelas memiliki beberapa tujuan, itu harus dibagi ke dalam kelas yang terpisah.
Pertimbangkan sebuah contoh:
<?php
namespace Demo;
use DB;
class OrdersReport
{
public function getOrdersInfo($startDate, $endDate)
{
$orders = $this->queryDBForOrders($startDate, $endDate);
return $this->format($orders);
}
protected function queryDBForOrders($startDate, $endDate)
{ // If we would update our persistence layer in the future,
// we would have to do changes here too. <=> reason to change!
return DB::table('orders')->whereBetween('created_at', [$startDate, $endDate])->get();
}
protected function format($orders)
{ // If we changed the way we want to format the output,
// we would have to make changes here. <=> reason to change!
return '<h1>Orders: ' . $orders . '</h1>';
}
}
. ? , (, ). .
, , , XML, JSON, HTML ..
:
<?php
namespace Report;
use Report\Repositories\OrdersRepository;
class OrdersReport
{
protected $repo;
protected $formatter;
public function __construct(OrdersRepository $repo, OrdersOutPutInterface $formatter)
{
$this->repo = $repo;
$this->formatter = $formatter;
}
public function getOrdersInfo($startDate, $endDate)
{
$orders = $this->repo->getOrdersWithDate($startDate, $endDate);
return $this->formatter->output($orders);
}
}
namespace Report;
interface OrdersOutPutInterface
{
public function output($orders);
}
namespace Report;
class HtmlOutput implements OrdersOutPutInterface
{
public function output($orders)
{
return '<h1>Orders: ' . $orders . '</h1>';
}
}
namespace Report\Repositories;
use DB;
class OrdersRepository
{
public function getOrdersWithDate($startDate, $endDate)
{
return DB::table('orders')->whereBetween('created_at', [$startDate, $endDate])->get();
}
}
/ (Open-closed Principle)
, .
(, , ) . , .
:
<?php
class Rectangle
{
public $width;
public $height;
public function __construct($width, $height)
{
$this->width = $width;
$this->height = $height;
}
}
class Circle
{
public $radius;
public function __construct($radius)
{
$this->radius = $radius;
}
}
class AreaCalculator
{
public function calculate($shape)
{
if ($shape instanceof Rectangle) {
$area = $shape->width * $shape->height;
} else {
$area = $shape->radius * $shape->radius * pi();
}
return $area;
}
}
$circle = new Circle(5);
$rect = new Rectangle(8,5);
$obj = new AreaCalculator();
echo $obj->calculate($circle);
,
AreaCalculator
. /, , .
? :
<?php
interface AreaInterface
{
public function calculateArea();
}
class Rectangle implements AreaInterface
{
public $width;
public $height;
public function __construct($width, $height)
{
$this->width = $width;
$this->height = $height;
}
public function calculateArea(){
$area = $this->height * $this->width;
return $area;
}
}
class Circle implements AreaInterface
{
public $radius;
public function __construct($radius)
{
$this->radius = $radius;
}
public function calculateArea(){
$area = $this->radius * $this->radius * pi();
return $area;
}
}
class AreaCalculator
{
public function calculate($shape)
{
$area = 0;
$area = $shape->calculateArea();
return $area;
}
}
$circle = new Circle(5);
$obj = new AreaCalculator();
echo $obj->calculate($circle);
,
AreaCalculator
.
(Liskov Substitution Principle)
“Data abstraction” 1987-. 1994-
:
φ(x) — x T. φ(y) y S, S — T.
, , :
- .
- .
- .
1996- , :
, , , .
: / / .
, () , . , , , , , , . .
:
<?php
interface LessonRepositoryInterface
{
/**
* Fetch all records.
*
* @return array
*/
public function getAll();
}
class FileLessonRepository implements LessonRepositoryInterface
{
public function getAll()
{
// return through file system
return [];
}
}
class DbLessonRepository implements LessonRepositoryInterface
{
public function getAll()
{
/*
Violates LSP because:
- the return type is different
- the consumer of this subclass and FileLessonRepository won't work identically
*/
// return Lesson::all();
// to fix this
return Lesson::all()->toArray();
}
}
(Interface Segregation Principle)
, .
, , .
, .
:
<?php
interface workerInterface
{
public function work();
public function sleep();
}
class HumanWorker implements workerInterface
{
public function work()
{
var_dump('works');
}
public function sleep()
{
var_dump('sleep');
}
}
class RobotWorker implements workerInterface
{
public function work()
{
var_dump('works');
}
public function sleep()
{
// No need
}
}
RobotWorker
’ ,
sleep
, . . :
<?php
interface WorkAbleInterface
{
public function work();
}
interface SleepAbleInterface
{
public function sleep();
}
class HumanWorker implements WorkAbleInterface, SleepAbleInterface
{
public function work()
{
var_dump('works');
}
public function sleep()
{
var_dump('sleep');
}
}
class RobotWorker implements WorkAbleInterface
{
public function work()
{
var_dump('works');
}
}
(Dependency Inversion Principle)
. .
. .
: , - .
, , , .
:
<?php
class MySQLConnection
{
/**
* db connection
*/
public function connect()
{
var_dump('MYSQL Connection');
}
}
class PasswordReminder
{
/**
* @var MySQLConnection
*/
private $dbConnection;
public function __construct(MySQLConnection $dbConnection)
{
$this->dbConnection = $dbConnection;
}
}
, « » « ». .
, ,
MySQLConnection
PasswordReminder
,
MySQLConnection
.
PasswordReminder
MySQLConnection
.
MySQLConnection
MongoDBConnection
,
PasswordReminder
.
PasswordReminder
, - . ? :
<?php
interface ConnectionInterface
{
public function connect();
}
class DbConnection implements ConnectionInterface
{
/**
* db connection
*/
public function connect()
{
var_dump('MYSQL Connection');
}
}
class PasswordReminder
{
/**
* @var ConnectionInterface
*/
private $dbConnection;
public function __construct(ConnectionInterface $dbConnection)
{
$this->dbConnection = $dbConnection;
}
}
MySQLConnection
MongoDBConnection
.
PasswordReminder
,
PasswordReminder
.