شرح بسيط لمبادئ SOLID



المبادئ SOLID هو معيار برمجة يجب على جميع المطورين فهمه جيدًا لتجنب إنشاء بنية ضعيفة. يستخدم هذا المعيار على نطاق واسع في OOP. إذا تم تطبيقه بشكل صحيح ، فإنه يجعل الشفرة أكثر قابلية للتوسعة ومنطقية وقابلة للقراءة. عندما ينشئ المطور تطبيقًا ، مسترشدًا بهندسة معمارية ضعيفة ، يتبين أن الرمز غير مرن ، حتى التغييرات الطفيفة فيه يمكن أن تؤدي إلى أخطاء. لذلك ، يجب عليك اتباع مبادئ SOLID.

سيستغرق الأمر بعض الوقت لإتقانها ، ولكن إذا كتبت رمزًا وفقًا لهذه المبادئ ، فستزداد جودتها ، وستتقن إنشاء بنية برامج جيدة.

لفهم مبادئ SOLID ، عليك أن تفهم بوضوح كيفية استخدام الواجهات. إذا لم يكن لديك مثل هذا الفهم ، فاقرأ الوثائق أولاً.

سأشرح SOLID بأبسط طريقة ، لذلك يسهل على المبتدئين اكتشافه. سننظر في المبادئ واحدا تلو الآخر.

مبدأ المسؤولية الفردية

هناك سبب واحد فقط يؤدي إلى تغيير الطبقة.
يجب أن يحل فصل واحد مشكلة واحدة فقط. قد يكون لها عدة طرق ، ولكن يجب استخدامها فقط لحل مشكلة عامة. يجب أن تخدم جميع الأساليب والخصائص غرضًا واحدًا. إذا كان للفصل عدة أغراض ، فيجب تقسيمه إلى فصول منفصلة.

فكر في مثال:

<?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.
, , :
  1. .
  2. .
  3. .
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 .

Source: https://habr.com/ru/post/ar412699/


All Articles