백엔드 개발 PHP 튜토리얼 PHP 객체 지향 설계(S.O.L.I.D)의 5가지 기본 원칙에 대해 이야기해 보겠습니다.

PHP 객체 지향 설계(S.O.L.I.D)의 5가지 기본 원칙에 대해 이야기해 보겠습니다.

Sep 07, 2022 pm 07:44 PM
php

이 기사는 PHP 객체 지향 설계(S.O.L.I.D)의 5가지 기본 원칙에 대해 이야기해 보겠습니다. 객체 지향 설계(S.O.L.I.D)의 5가지 기본 원칙을 안내합니다. 도움이 되기를 바랍니다.

PHP 객체 지향 설계(S.O.L.I.D)의 5가지 기본 원칙에 대해 이야기해 보겠습니다.

S.O.L.I.D는 Bob 삼촌으로 더 잘 알려진 Robert C. Martin이 제안한 객체 지향 디자인(OOD)의 5가지 원칙의 약어입니다.

이러한 지침을 사용하면 확장 가능하고 유지 관리 가능한 소프트웨어를 더 쉽게 개발할 수 있습니다. 또한 코드를 더욱 간소화하고 리팩토링하기 쉽게 만듭니다. 또한 민첩한 개발 및 적응형 소프트웨어 개발의 일부입니다.

Notes: 이 글은 "Welcome to _*S.O.L.I.D*" 글에 대한 단순한 소개가 아니며, 이 글은 *S.O.L.I.D***가 무엇인지 명확히 하고자 합니다.

S.O.L.I.D는 다음을 의미합니다.

확장된 약어는 복잡해 보이지만 실제로는 꽤 이해하기 쉽습니다.

  • S - 단일 함수 원칙
  • O - 열기 및 닫기 원칙
  • L - Liskov 대체 원칙
  • I - 인터페이스 격리 원칙
  • D - 종속성 반전 원칙
S.O.L.I.D가 우리가 더 나은 개발자가 되는 데 도움이 되는 이유를 이해하기 위해 각 원칙을 살펴보겠습니다.

단일 책임 원칙

약어는

S.R.P입니다. 이 원칙의 내용은 다음과 같습니다.

클래스는 클래스를 변경하는 요소를 하나만 가질 수 있습니다. 하나의 책임이 있습니다.

예를 들어, 몇 가지 모양이 있고 이러한 모양의 전체 면적을 계산하려고 한다고 가정해 보겠습니다. 네, 쉽죠?

class Circle {
    public $radius;

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

class Square {
    public $length;

    public function __construct($length) {
        $this->length = $length;
    }
}
로그인 후 복사
먼저 그래픽 클래스를 생성하고 이 클래스의 생성자가 필요한 매개변수를 초기화합니다. 다음으로

AreaCalculator 클래스를 생성한 후, 지정된 도형의 전체 면적을 계산하는 논리 코드를 작성합니다.

class AreaCalculator {

    protected $shapes;

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

    public function sum() {
        // logic to sum the areas
    }

    public function output() {
        return 'Sum of the areas of provided shapes: ' . $this->sum();
    }
}
로그인 후 복사

AreaCalculator 이 메서드를 사용하려면 이 클래스를 인스턴스화하고 그래픽 배열을 전달하여 페이지 하단에 출력 콘텐츠를 표시하면 됩니다.

$shapes = array(
    new Circle(2),
    new Square(5),
    new Square(6)
);

$areas = new AreaCalculator($shapes);

echo $areas->output();
로그인 후 복사
출력 방법의 문제점은

AreaCalculator가 데이터 출력 로직을 처리한다는 것입니다. 그렇다면 사용자가 json이나 다른 형식으로 데이터를 출력하고 싶다면 어떻게 해야 할까요?

모든 로직은 SRP(단일 책임 원칙)를 정확히 위반하는

AreaCalculator 클래스에 의해 처리됩니다. AreaCalculator 클래스는 그래프의 전체 영역 계산만 담당해야 하며, 사용자는 json 또는 HTML 형식의 데이터를 원합니다.

따라서 이 문제를 해결하려면

SumCalculatorOutputter 클래스를 생성하고 이를 사용하여 모든 그래프의 전체 영역이 표시되는 방법에 대한 필수 표시 로직을 처리할 수 있습니다.

SumCalculatorOutputter 클래스는 다음과 같이 작동합니다.

$shapes = array(
    new Circle(2),
    new Square(5),
    new Square(6)
);

$areas = new AreaCalculator($shapes);
$output = new SumCalculatorOutputter($areas);

echo $output->JSON();
echo $output->HAML();
echo $output->HTML();
echo $output->JADE();
로그인 후 복사
이제 사용자에게 출력하려는 ​​데이터 형식은

SumCalculatorOutputter 클래스에 의해 처리됩니다.

열림과 닫힘의 원칙

객체와 엔터티는 확장을 위해 열려야 하고, 수정을 위해 닫혀 있어야 합니다.

간단히 말하면 클래스는 자체 수정 없이 쉽게 기능을 확장할 수 있어야 합니다.

AreaCalculator 클래스, 특히 sum 메서드를 살펴보겠습니다.

public function sum() {
    foreach($this->shapes as $shape) {
        if(is_a($shape, 'Square')) {
            $area[] = pow($shape->length, 2);
        } else if(is_a($shape, 'Circle')) {
            $area[] = pi() * pow($shape->radius, 2);
        }
    }

    return array_sum($area);
}
로그인 후 복사

sum 방법을 사용하여 더 많은 도형의 면적을 계산하려면 if/else 블록을 더 추가해야 하지만 이는 열기 및 닫기 원칙에 위배됩니다.

sum 방법을 더 좋게 만드는 방법은 각 모양의 면적을 계산하는 코드 로직을 sum 방법에서 옮겨 각 모양 클래스에 넣는 것입니다.

class Square {
    public $length;

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

    public function area() {
        return pow($this->length, 2);
    }
}
로그인 후 복사
동일한 작업을 사용해야 합니다.

Circle 클래스를 처리하고 클래스에 area 메소드를 추가하세요. 이제 모든 모양의 영역 합계를 계산하는 것은 다음과 같이 간단해야 합니다.

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

    return array_sum($area);
}
로그인 후 복사
다음으로 다른 모양 클래스를 만들고 코드를 손상하지 않고 합계를 계산할 때 이를 전달할 수 있습니다. 하지만 이제 또 다른 질문이 생깁니다.

AreaCalculator에 전달된 개체가 실제로 모양인지 또는 모양 개체에 area 메서드가 있는지 어떻게 알 수 있습니까?

인터페이스 코딩은

S.O.L.I.D 연습의 일부입니다. 예를 들어 다음 예에서는 각 모양 클래스가 구현할 인터페이스 클래스를 만듭니다.

interface ShapeInterface {
    public function area();
}

class Circle implements ShapeInterface {
    public $radius;

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

    public function area() {
        return pi() * pow($this->radius, 2);
    }
}
로그인 후 복사

AreaCalculator의 sum 메서드에서 제공된 인스턴스가 모양 클래스는 ShapeInterface의 구현입니다. 그렇지 않으면 예외가 발생합니다.

public function sum() {
    $area = [];
    foreach($this->shapes as $shape) {
        if(is_a($shape, 'ShapeInterface')) {
            $area[] = $shape->area();
            continue;
        }

        throw new AreaCalculatorInvalidShapeException;
    }

    return array_sum($area);
}
로그인 후 복사

里氏替换原则

如果对每一个类型为 T1的对象 o1,都有类型为 T2 的对象o2,使得以 T1定义的所有程序 P 在所有的对象 o1 都代换成 o2 时,程序 P 的行为没有发生变化,那么类型 T2 是类型 T1 的子类型。

这句定义的意思是说:每个子类或者衍生类可以毫无问题地替代基类/父类。

依然使用 AreaCalculator 类, 假设我们有一个 VolumeCalculator 类,这个类继承了  AreaCalculator 类:

class VolumeCalculator extends AreaCalulator {
    public function construct($shapes = array()) {
        parent::construct($shapes);
    }

    public function sum() {
        // logic to calculate the volumes and then return and array of output
        return array($summedData);
    }
}
로그인 후 복사

SumCalculatorOutputter 类:

class SumCalculatorOutputter {
    protected $calculator;

    public function __constructor(AreaCalculator $calculator) {
        $this->calculator = $calculator;
    }

    public function JSON() {
        $data = array(
            'sum' => $this->calculator->sum();
        );

        return json_encode($data);
    }

    public function HTML() {
        return 'Sum of the areas of provided shapes: ' . $this->calculator->sum();
    }
}
로그인 후 복사

如果我们运行像这样一个例子:

$areas = new AreaCalulator($shapes);
$volumes = new VolumeCalculator($solidShapes);

$output = new SumCalculatorOutputter($areas);
$output2 = new SumCalculatorOutputter($volumes);
로그인 후 복사

程序不会出问题, 但当我们使用$output2 对象调用 HTML 方法时 ,我们接收到一个 E_NOTICE 错误,提示我们 数组被当做字符串使用的错误。

为了修复这个问题,只需:

public function sum() {
    // logic to calculate the volumes and then return and array of output
    return $summedData;
}
로그인 후 복사

而不是让VolumeCalculator 类的 sum 方法返回数组。

$summedData 是一个浮点数、双精度浮点数或者整型。

接口隔离原则

使用方(client)不应该依赖强制实现不使用的接口,或不应该依赖不使用的方法。

继续使用上面的 shapes 例子,已知拥有一个实心块,如果我们需要计算形状的体积,我们可以在 ShapeInterface 中添加一个方法:

interface ShapeInterface {
    public function area();
    public function volume();
}
로그인 후 복사

任何形状创建的时候必须实现 volume 方法,但是【平面】是没有体积的,实现这个接口会强制的让【平面】类去实现一个自己用不到的方法。

ISP 原则不允许这么去做,所以我们应该创建另外一个拥有 volume 方法的SolidShapeInterface 接口去代替这种方式,这样类似立方体的实心体就可以实现这个接口了:

interface ShapeInterface {
    public function area();
}

interface SolidShapeInterface {
    public function volume();
}

class Cuboid implements ShapeInterface, SolidShapeInterface {
    public function area() {
        //计算长方体的表面积
    }

    public function volume() {
        // 计算长方体的体积
    }
}
로그인 후 복사

这是一个更好的方式,但是要注意提示类型时不要仅仅提示一个 ShapeInterfaceSolidShapeInterface
你能创建其它的接口,比如 ManageShapeInterface ,并在平面和立方体的类上实现它,这样你能很容易的看到有一个用于管理形状的api。例:

interface ManageShapeInterface {
    public function calculate();
}

class Square implements ShapeInterface, ManageShapeInterface {
    public function area() { /Do stuff here/ }

    public function calculate() {
        return $this->area();
    }
}

class Cuboid implements ShapeInterface, SolidShapeInterface, ManageShapeInterface {
    public function area() { /Do stuff here/ }
    public function volume() { /Do stuff here/ }

    public function calculate() {
        return $this->area() + $this->volume();
    }
}
로그인 후 복사

现在在 AreaCalculator 类中,我们可以很容易地用 calculate替换对area 方法的调用,并检查对象是否是 ManageShapeInterface 的实例,而不是 ShapeInterface

依赖倒置原则

最后,但绝不是最不重要的:

实体必须依赖抽象而不是具体的实现.即高等级模块不应该依赖低等级模块,他们都应该依赖抽象.

这也许听起来让人头大,但是它很容易理解.这个原则能够很好的解耦,举个例子似乎是解释这个原则最好的方法:

class PasswordReminder {
    private $dbConnection;

    public function __construct(MySQLConnection $dbConnection) {
        $this->dbConnection = $dbConnection;
    }
}
로그인 후 복사

首先 MySQLConnection 是低等级模块,然而 PasswordReminder 是高等级模块,但是根据 S.O.L.I.D. 中 D 的解释:依赖于抽象而不依赖与实现, 上面的代码段违背了这一原则,因为 PasswordReminder 类被强制依赖于 MySQLConnection 类.

稍后,如果你希望修改数据库驱动,你也不得不修改 PasswordReminder 类,因此就违背了 Open-close principle

PasswordReminder 类不应该关注你的应用使用了什么数据库,为了进一步解决这个问题,我们「面向接口写代码」,由于高等级和低等级模块都应该依赖于抽象,我们可以创建一个接口:

interface DBConnectionInterface {
    public function connect();
}
로그인 후 복사

这个接口有一个连接数据库的方法,MySQLConnection 类实现该接口,在 PasswordReminder 的构造方法中不要直接将类型约束设置为 MySQLConnection 类,而是设置为接口类,这样无论你的应用使用什么类型的数据库,PasswordReminder 类都能毫无问题地连接数据库,且不违背 开闭原则

class MySQLConnection implements DBConnectionInterface {
    public function connect() {
        return "Database connection";
    }
}

class PasswordReminder {
    private $dbConnection;

    public function __construct(DBConnectionInterface $dbConnection) {
        $this->dbConnection = $dbConnection;
    }
}
로그인 후 복사

从上面一小段代码,你现在能看出高等级和低等级模块都依赖于抽象了。

总结

说实话,S.O.L.I.D 一开始似乎很难掌握,但只要不断地使用和遵守其原则,它将成为你的一部分,使你的代码易被扩展、修改,测试,即使重构也不容易出现问题。

추천 학습: "PHP 객체 지향 설계(S.O.L.I.D)의 5가지 기본 원칙에 대해 이야기해 보겠습니다. 비디오 튜토리얼"

위 내용은 PHP 객체 지향 설계(S.O.L.I.D)의 5가지 기본 원칙에 대해 이야기해 보겠습니다.의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.

핫 AI 도구

Undresser.AI Undress

Undresser.AI Undress

사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover

AI Clothes Remover

사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool

Undress AI Tool

무료로 이미지를 벗다

Clothoff.io

Clothoff.io

AI 옷 제거제

AI Hentai Generator

AI Hentai Generator

AI Hentai를 무료로 생성하십시오.

뜨거운 도구

메모장++7.3.1

메모장++7.3.1

사용하기 쉬운 무료 코드 편집기

SublimeText3 중국어 버전

SublimeText3 중국어 버전

중국어 버전, 사용하기 매우 쉽습니다.

스튜디오 13.0.1 보내기

스튜디오 13.0.1 보내기

강력한 PHP 통합 개발 환경

드림위버 CS6

드림위버 CS6

시각적 웹 개발 도구

SublimeText3 Mac 버전

SublimeText3 Mac 버전

신 수준의 코드 편집 소프트웨어(SublimeText3)

CakePHP 프로젝트 구성 CakePHP 프로젝트 구성 Sep 10, 2024 pm 05:25 PM

이번 장에서는 CakePHP의 환경 변수, 일반 구성, 데이터베이스 구성, 이메일 구성에 대해 알아봅니다.

Ubuntu 및 Debian용 PHP 8.4 설치 및 업그레이드 가이드 Ubuntu 및 Debian용 PHP 8.4 설치 및 업그레이드 가이드 Dec 24, 2024 pm 04:42 PM

PHP 8.4는 상당한 양의 기능 중단 및 제거를 통해 몇 가지 새로운 기능, 보안 개선 및 성능 개선을 제공합니다. 이 가이드에서는 Ubuntu, Debian 또는 해당 파생 제품에서 PHP 8.4를 설치하거나 PHP 8.4로 업그레이드하는 방법을 설명합니다.

CakePHP 날짜 및 시간 CakePHP 날짜 및 시간 Sep 10, 2024 pm 05:27 PM

cakephp4에서 날짜와 시간을 다루기 위해 사용 가능한 FrozenTime 클래스를 활용하겠습니다.

CakePHP 파일 업로드 CakePHP 파일 업로드 Sep 10, 2024 pm 05:27 PM

파일 업로드 작업을 위해 양식 도우미를 사용할 것입니다. 다음은 파일 업로드의 예입니다.

CakePHP 라우팅 CakePHP 라우팅 Sep 10, 2024 pm 05:25 PM

이번 장에서는 라우팅과 관련된 다음과 같은 주제를 학습하겠습니다.

CakePHP 토론 CakePHP 토론 Sep 10, 2024 pm 05:28 PM

CakePHP는 PHP용 오픈 소스 프레임워크입니다. 이는 애플리케이션을 훨씬 쉽게 개발, 배포 및 유지 관리할 수 있도록 하기 위한 것입니다. CakePHP는 강력하고 이해하기 쉬운 MVC와 유사한 아키텍처를 기반으로 합니다. 모델, 뷰 및 컨트롤러 gu

PHP 개발을 위해 Visual Studio Code(VS Code)를 설정하는 방법 PHP 개발을 위해 Visual Studio Code(VS Code)를 설정하는 방법 Dec 20, 2024 am 11:31 AM

VS Code라고도 알려진 Visual Studio Code는 모든 주요 운영 체제에서 사용할 수 있는 무료 소스 코드 편집기 또는 통합 개발 환경(IDE)입니다. 다양한 프로그래밍 언어에 대한 대규모 확장 모음을 통해 VS Code는

CakePHP 유효성 검사기 만들기 CakePHP 유효성 검사기 만들기 Sep 10, 2024 pm 05:26 PM

컨트롤러에 다음 두 줄을 추가하면 유효성 검사기를 만들 수 있습니다.

See all articles