견고한 원칙-PHP의 개체 지향 프로그래밍⭐⭐⭐⭐⭐

SOLID는 Robert C.Martin(일명 Bob 아저씨)이 제기한 다섯 가지 대상 디자인(OOD) 원칙의 알파벳 줄임말이다.
이러한 원칙은 소프트웨어 개발에 도움이 되는 실천을 세웠고 프로젝트의 발전에 따라 유지보수와 확장을 고려했다.이러한 실천을 채택하는 것도 코드 냄새를 피하고 코드를 재구성하며 민첩하거나 소프트웨어 개발에 적응하는 데 도움이 된다.
SOLID 담당자:
S-단일 책임 원칙
O-개폐 원리
L-Liskov 교체 원리
I. 인터페이스 격리 원칙
역치 원리에 의존하다
이제 첫 번째:
단일 책임 원칙

"A Class Should Have One, And Only One Responsibility"


이것은 만약 우리 반이 한 가지 책임을 지지 않는다면 우리는 고도의 결합을 할 수 있다는 것을 의미한다.왜냐하면 우리의 코드는 어떤 변경도 취약하기 때문이다.
다음과 같은 사용자 클래스가 있다고 가정해 봅시다.
<?php

class User {

    private $email;

    // Getter and setter...

    public function store() {
        // Store attributes into a database...
    }
}
이런 상황에서 방법store이 범위를 넘어서면 이 직책은 데이터베이스를 관리하는 유형에 속해야 한다.
이곳의 해결 방안은 두 개의 클래스를 만들고 각 클래스는 적당한 직책을 가진다.
<?php

class User {

    private $email;

    // Getter and setter...
}

class UserDB {

    public function store(User $user) {
        // Store the user into a database...
    }
}
이제 고체 중의 O에 대해 계속 토론합시다
개폐 원리

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


이 원칙에 따라 소프트웨어 실체는 반드시 쉽게 확장되고 새로운 기능을 갖추어야 하며 사용 중인 기존 코드를 수정할 필요가 없다.
가령 우리가 반드시 일부 물체의 총면적을 계산해야 한다고 가정한다면, 이를 하려면, 우리는 AreaCalculator류가 필요하다. 이것은 각 형상 면적의 총계만 계산한다.
문제는 모양마다 자신의 면적을 계산하는 방법이 다르다는 것이다.
<?php

class Rectangle {

    public $width;
    public $height;

    public function __construct($width, $height) {
        $this->width = $width;
        $this->height = $height;
    }
}

class Square {

    public $length;

    public function __construct($length) {
        $this->length = $length;
    }
}


class AreaCalculator {

    protected $shapes;

    public function __construct($shapes = array()) {
        $this->shapes = $shapes;
    }

    public function sum() {
        $area = [];

        foreach($this->shapes as $shape) {
            if($shape instanceof Square) {
                $area[] = pow($shape->length, 2);
            } else if($shape instanceof Rectangle) {
                $area[] = $shape->width * $shape->height;
            }
        }

        return array_sum($area);
    }
}
만약 우리가 aCircle와 같은 다른 형상을 추가한다면, 우리는 AreaCalculator를 바꾸어 새로운 형상 면적을 계산해야 한다. 이것은 지속가능하지 않다.
이곳의 해결 방안은 간단한 Shape 인터페이스를 만드는 것이다. 이 인터페이스는 면적 방법을 가지고 모든 다른 형태로 실현될 것이다.
<?php

interface Shape {
    public function area();
}

class Rectangle implements Shape {

    private $width;
    private $height;

    public function __construct($width, $height) {
        $this->width = $width;
        $this->height = $height;
    }

    public function area() {
        return $this->width * $this->height;
    }
}

class Square implements Shape {

    private $length;

    public function __construct($length) {
        $this->length = $length;
    }

    public function area() {
        return pow($this->length, 2);
    }
}


class AreaCalculator {

    protected $shapes;

    public function __construct($shapes = array()) {
        $this->shapes = $shapes;
    }

    public function sum() {
        $area = [];

        foreach($this->shapes as $shape) {
            $area[] = $shape->area();
        }

        return array_sum($area);
    }
}
이렇게 하면, 우리는 하나의 방법으로만 계산하고, 만약 우리가 새로운 모양을 추가해야 한다면, 이것은 Shape 인터페이스만 실현될 것이다.
SOLID L의 세 번째 원칙은 다음과 같습니다.
리스코프 대체 원리

Let q(x) be a property provable about objects of x of type T. Then q(y) should be provable for objects y of type S where S is a subtype of T.


이 원칙에 따르면 대상은 반드시 하위 유형의 실례로 교체되어야 하며 시스템의 정확한 기능을 바꾸지 않는다고 한다.
나는 이것이 이해하기 어렵다는 것을 안다. 그래서 나는 뜻을 다섯 부분으로 나눈다.
1. Child function arguments must match function arguments of parent

2. Child function return type must match parent function return type

3. Child pre-conditions cannot be greater than parent function pre-conditions

4. Child function post-conditions cannot be lesser than parent function post-conditions.

5. Exceptions thrown by child method must be the same as or inherit from an exception thrown by the parent method.
이 점을 완전히 이해하려면 다음과 같은 장면이 있다.
두 가지 유형의 커피 머신을 관리한다고 상상해 보세요.사용자의 계획에 따라 우리는 기본 또는 고급 커피 머신을 사용할 것이다. 유일한 차이점은 고급 커피 머신이 기본 커피 머신으로 만든 바닐라 커피보다 더 좋다는 것이다.
<?php

interface CoffeeMachineInterface {
    public function brewCoffee($selection);
}


class BasicCoffeeMachine implements CoffeeMachineInterface {

    public function brewCoffee($selection) {
        switch ($selection) {
            case 'ESPRESSO':
                return $this->brewEspresso();
            default:
                throw new CoffeeException('Selection not supported');
        }
    }

    protected function brewEspresso() {
        // Brew an espresso...
    }
}


class PremiumCoffeeMachine extends BasicCoffeeMachine {

    public function brewCoffee($selection) {
        switch ($selection) {
            case 'ESPRESSO':
                return $this->brewEspresso();
            case 'VANILLA':
                return $this->brewVanillaCoffee();
            default:
                throw new CoffeeException('Selection not supported');
        }
    }

    protected function brewVanillaCoffee() {
        // Brew a vanilla coffee...
    }
}


function getCoffeeMachine(User $user) {
    switch ($user->getPlan()) {
        case 'PREMIUM':
            return new PremiumCoffeeMachine();
        case 'BASIC':
        default:
            return new BasicCoffeeMachine();
    }
}


function prepareCoffee(User $user, $selection) {
    $coffeeMachine = getCoffeeMachine($user);
    return $coffeeMachine->brewCoffee($selection);
}
두 기계의 주 프로그램 행위는 반드시 같아야 한다.
내가 대표하는 네 번째 원칙은:
인터페이스 분리 원리

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.


이 원칙은 영원히 사용할 수 없는 인터페이스를 실현해서는 안 된다는 유형을 정의했다.
이런 상황에서 이것은 우리의 실현 과정에서 우리가 필요로 하지 않는 방법을 가질 수 있다는 것을 의미한다.
해결 방안은 일반적인 인터페이스가 아니라 특정한 인터페이스를 개발하는 것이다.
다음은 우리가 발명FutureCar비행도 할 수 있고 운전도 할 수 있다고 상상하는 장면이다.
<?php

interface VehicleInterface {
    public function drive();
    public function fly();
}

class FutureCar implements VehicleInterface {

    public function drive() {
        echo 'Driving a future car!';
    }

    public function fly() {
        echo 'Flying a future car!';
    }
}

class Car implements VehicleInterface {

    public function drive() {
        echo 'Driving a car!';
    }

    public function fly() {
        throw new Exception('Not implemented method');
    }
}

class Airplane implements VehicleInterface {

    public function drive() {
        throw new Exception('Not implemented method');
    }

    public function fly() {
        echo 'Flying an airplane!';
    }
}
보시다시피 주요 문제는 자동차와Airplane 사용하지 않는 방법이 있다는 것이다.
해결 방안은 VehicleInterface를 두 개의 더 구체적인 인터페이스로 나누어 필요할 때만 사용하는 것이다. 아래와 같다.
<?php

interface CarInterface {
    public function drive();
}

interface AirplaneInterface {
    public function fly();
}

class FutureCar implements CarInterface, AirplaneInterface {

    public function drive() {
        echo 'Driving a future car!';
    }

    public function fly() {
        echo 'Flying a future car!';
    }
}

class Car implements CarInterface {

    public function drive() {
        echo 'Driving a car!';
    }
}

class Airplane implements AirplaneInterface {

    public function fly() {
        echo 'Flying an airplane!';
    }
}
마지막으로 가장 중요하지 않은 것은 D가 아니다. D는 다음과 같다.
역치 원리에 의존하다

Entities must depend on abstractions not on concretions. It states that the high level module must not depend on the low level module, but they should depend on abstractions.


이 원칙은 특정한 클래스가 다른 클래스에 직접적으로 의존해서는 안 되고 이 클래스의 추상에 의존해야 한다는 것을 의미한다.
이 원칙은 결합과 더 높은 코드의 중용성을 허용한다.UserDB류의 첫 번째 예시를 살펴보자.이러한 유형은 데이터베이스 연결에 종속될 수 있습니다.
<?php

class UserDB {

    private $dbConnection;

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

    public function store(User $user) {
        // Store the user into a database...
    }
}
이 예에서 UserDB 클래스는 MySQL 데이터베이스에 직접 의존한다.
이것은 우리가 사용하고 있는 데이터베이스 엔진을 바꾸려면 이 종류를 다시 쓰고 개폐 원칙을 위반해야 한다는 것을 의미한다.
해결 방안은 데이터베이스 연결을 개발하는 추상적인 것이다.
<?php

interface DBConnectionInterface {
    public function connect();
}

class MySQLConnection implements DBConnectionInterface {

    public function connect() {
        // Return the MySQL connection...
    }
}

class UserDB {

    private $dbConnection;

    public function __construct(DBConnectionInterface $dbConnection) {
        $this->dbConnection = $dbConnection;
    }

    public function store(User $user) {
        // Store the user into a database...
    }
}
이 코드는 고급과 저급 모듈이 추상에 의존하고 있음을 확인한다.

Hurray! We are done with the 5 SOLID Principle of Object Oriented Programming! You can use these principles represent the state of the art of the code quality and following them permit you to write software that will be easily extended, reusable and refactored.

Projects that adhere to SOLID principles can be shared with collaborators, extended, modified, tested, and refactored with fewer complications.

좋은 웹페이지 즐겨찾기