PHP의 디자인 패턴 소개(및 Drupal에서 활용)
게시 됨: 2022-07-05똑똑한 누군가가 말한 적이 있습니다. 좋은 코더 코드, 뛰어난 재사용.
개발자는 종종 동일한 유형의 문제를 반복적으로 해결하는 자신을 발견합니다. 코드 재사용은 진정으로 소프트웨어 개발의 성배입니다. 또한 누가 잘 구성된 코드를 읽고 쓰기를 좋아하지 않습니까? Enter - PHP로 패턴을 디자인합니다.
PHP 디자인 패턴은 개발자에게 매우 유용한 것으로 입증되었으며 엄청난 문제 해결자입니다. 모범 사례를 따르는 것은 효율적인 코드를 작성하는 데 중요합니다. PHP 디자인 패턴은 이제 Drupal 9 프로젝트에서도 사용되는 객체 지향 프로그래밍(OOP) 개념입니다. Drupal은 버전 8부터 최신 PHP 및 OOP 개념을 채택하여 보다 깨끗하고 강력한 프로그래밍을 위해 디자인 패턴을 활용할 수 있습니다. 이 기사에서는 PHP에서 일반적으로 사용되는 몇 가지 디자인 패턴과 Drupal에서 종속성 주입과 같은 패턴을 사용하는 방법에 대해 설명합니다.
아직도 Drupal 7을 사용 중이신가요? 이 기사를 읽고 Drupal 9 마이그레이션을 준비하는 데 도움이 되는 편리한 체크리스트를 찾으십시오.
PHP의 디자인 패턴이란?
소프트웨어 엔지니어링에서 디자인 패턴은 소프트웨어 디자인에서 일반적으로 발생하는 문제에 대한 일반적으로 반복 가능한 솔루션입니다. 좋은 객체 지향 디자인은 재사용 가능하고 유지 관리 가능하며 확장 가능해야 하며 PHP의 디자인 패턴은 그렇게 하는 데 매우 도움이 될 수 있습니다. 이는 문제 해결에 도움이 될 뿐만 아니라 일반적인 문제를 해결하는 최적의 방법을 의미합니다.
PHP 디자인 패턴을 사용하는 이유
PHP에서 디자인 패턴을 구현하는 가장 중요한 이점은 다음과 같습니다.
- PHP 디자인 패턴은 개발 중에 직면하는 반복적인 문제를 해결하는 데 도움이 됩니다.
- PHP에서 디자인 패턴을 사용하면 디자이너와 개발자 간의 커뮤니케이션이 보다 효율적입니다.
- 디자인 패턴을 따르기 때문에 다른 개발자가 코드를 이해할 것이라고 확신할 수 있습니다.
- 모범 사례를 따르면 더 강력한 애플리케이션을 구축하는 데 도움이 됩니다.
- 개발을 더 빠르고 쉽게 만드는 데 도움이 됩니다.
PHP에서 널리 사용되는 디자인 패턴
디자인 패턴은 유사한 문제를 해결하기 위해 다양한 상황에서 사용될 수 있습니다. 생성 패턴, 구조 패턴 및 행동 패턴의 세 가지 유형으로 크게 분류할 수 있는 30개 이상의 디자인 패턴이 있습니다.
생성 패턴: 객체 생성 메커니즘에 사용되는 디자인 패턴으로, 객체를 구현한 시스템에서 분리할 수 있는 객체를 생성합니다.
구조적 패턴: 엔티티 간의 관계를 실현하는 간단한 방법을 식별하여 설계를 용이하게 합니다.
행동 패턴: 객체 간의 관계, 책임 및 알고리즘을 관리하는 데 사용됩니다.
공장 패턴
팩토리 패턴은 객체를 빌드하는 데 사용됩니다. 맞습니다. 개체를 만들지 말고 개체를 만드십시오. 객체를 빌드할 때 먼저 생성한 다음 초기화합니다. 일반적으로 특정 논리를 적용하고 여러 단계를 수행해야 합니다. 이를 통해 모든 것을 한 곳에 모아 동일한 방식으로 새 객체를 구축해야 할 때마다 재사용하는 것이 합리적입니다. 기본적으로 팩토리 패턴을 사용하는 것입니다.
우리 팩토리에 대한 인터페이스를 갖고 구체적인 팩토리가 아닌 그것에 의존하는 코드를 갖는 것은 좋은 생각입니다.
interface FamilyFactoryInterface { public function create() : Family }
다음으로 다음 클래스를 사용하여 팩토리 인터페이스를 구현합니다.
class FamilyFactory implements FamilyFactoryInterface { public function create() : Family { $family = new Family(); // initialize your family return $family; } }
어댑터 패턴
어댑터 디자인 패턴에서 클래스는 한 클래스의 인터페이스를 다른 클래스로 변환합니다. 이 예제에는 getTitle() 및 getAuthor() 메서드가 있는 TextBook 클래스가 있습니다. 클라이언트는 getTitleAndAuthor() 메소드를 기대합니다. demoAdapter 용 SimpleBook 을 "적응"하기 위해 TextBook의 인스턴스를 가져오고 고유한 getTitleAndAuthor 메서드에서 TextBook getTitle() 및 getAuthor() 메서드를 사용하는 어댑터 클래스인 BookAdapter 가 있습니다.
<?php class TextBook { private $title; private $author; function __construct($title_in, $author_in) { $this->title = $title_in; $this->author = $author_in; } function getTitle() { return $this->title; } function getAuthor() { return $this->author; } } class BookAdapter { private $book; function __construct(TextBook $book_in) { $this->book = $book_in; } function getTitleAndAuthors() { return $this->book->getTitle().' by '.$this->book->getAuthor(); } } // client writeln('BEGIN TESTING ADAPTER PATTERN'); writeln(''); $book = new TextBook("Gamma, Helm, Johnson, and Vlissides", "Design Patterns"); $bookAdapter = new BookAdapter($book); writeln('Author and Title: '.$bookAdapter->getTitleAndAuthor()); writeln(''); writeln('END TESTING ADAPTER PATTERN'); function writeln($line_in) { echo $line_in."<br/>"; } ?>
PHP 싱글톤 패턴
클래스의 인스턴스화를 단일 객체로 제한하기 위해 PHP의 싱글톤 패턴이 사용됩니다. 이는 시스템 전체에서 하나의 개체만 필요할 때 유용할 수 있습니다. 웹 응용 프로그램을 디자인하는 동안 특정 클래스의 한 인스턴스에만 액세스를 허용하는 것이 좋습니다. Singleton 패턴 클래스에서 명시적인 객체 생성을 방지하기 위해 private 생성자를 사용합니다.
<?php class Singleton { public static function getInstance() { static $instance = null; if (null === $instance) { $instance = new static(); } return $instance; } protected function __construct() { } private function __clone() { } private function __wakeup() { } } class SingletonChild extends Singleton { } $obj = Singleton::getInstance(); var_dump($obj === Singleton::getInstance()); $obj2 = SingletonChild::getInstance(); var_dump($obj2 === Singleton::getInstance()); var_dump($obj2 === SingletonChild::getInstance()); ?>
PHP의 관찰자 패턴
PHP 옵저버 패턴은 특정 장소의 특정 이벤트에 대해 나머지 시스템에 경고하는 데 사용됩니다.
예를 들어, 비평가들에게 영화를 보여주기 위해 극장 을 만들어야 하는 경우입니다. 현재 메서드로 Theatre 클래스를 정의합니다. 영화를 상영하기 전에 우리는 비평가들의 휴대폰으로 메시지를 보내고 싶다. 그런 다음 영화 중간에 비평가들에게 휴식 시간을 주기 위해 5분 동안 영화를 멈추고 싶습니다. 마지막으로, 영화가 끝난 후 비평가들에게 그들의 반응을 남겨달라고 요청하고 싶습니다. 따라서 PHP용 옵저버 패턴에서 옵저버 객체는 상태가 변경될 때만 알림을 받습니다.
코드는 이렇게 생겼습니다 -
class Theater { public function current(Movie $movie) : void { $critics = $movie->getCritics(); $this->message->send($critics, '...'); $movie->play(); $movie->pause(5); $this->progress->interval($critics) $movie->end(); $this->response->request($critics); } }
PHP용 데코레이터 패턴
데코레이터 패턴은 런타임에 개체의 특성을 변경하여 불필요한 상속과 클래스 수를 줄이려는 경우에 사용됩니다. 예를 들어 설명할 수 있습니다. Sofa와 Bed 클래스가 있고 둘 다 SleeperInterface를 구현한다고 가정해 보겠습니다.
interface SleeprInterface { public function sleep() : void; } class Sofa implements SleeperInterface { public function sleep() : void { // sleeps on sofa } } class Bed implements SleeperInterface { public function sleep() : void { // sleeps on bed } }
소파와 침대는 모두 같은 행동을 취합니다. 이제 사용자가 소파나 침대에서 잘 때 수면 추적을 알려주는 추가 기능이 있는 다른 소파와 침대가 필요합니다. 상속을 사용하면 다음과 같이 이 문제를 해결할 수 있습니다.
class SmartSofa extends Sofa { public function sleep() : void { parent::sleep(); $this->sleepHours(); } } class SmartBed extends Window { public function sleep() : void { parent::sleep(); $this->sleepHours(); } }
이제 총 4개의 클래스가 있습니다. 그러나 우리는 Decorator 패턴으로만 3개의 클래스로 이 문제를 해결할 수 있습니다. 방법은 다음과 같습니다.
class SmartSleeper implements SleeperInterface { private $sleeper; public function __construct(SleeperInterface $sleeper) { $this->sleeper = $sleeper; } public function sleep() : void { $this->sleeper->sleep(); $this->sleepHours(); } } $sofa = new Sofa(); $bed = new Bed(); $smartSofa = new SmartSleeper($sofa); $smartBed = new SmartSleeper($bed);
여기에서 프록시처럼 작동하지만 그 위에 추가 기능이 있는 새로운 유형의 슬리퍼를 도입했습니다.
Drupal 9의 디자인 패턴 활용
Drupal 9 이전에는 Drupal에 이미 많은 디자인 패턴이 설정되어 있지만 이전에는 사용할 수 없었던 더 많은 패턴이 있습니다. 이러한 새로운 패턴 중 일부는 이전 패턴을 완전히 대체하고 다른 일부는 Drupal 9에 몇 가지 새로운 기능을 도입합니다.
Drupal 9에서 사용되는 디자인 패턴은 다음과 같습니다.
- 객체 지향 프로그래밍 패턴(OOP)
- 의존성 주입
- 공장 패턴
- 싱글톤 패턴
OOP는 실제로 단일 패턴이 아니라 디자인 패턴을 훨씬 뛰어넘는 코드를 개념화하고 구조화하는 완전히 급진적인 방법입니다. 이것은 Drupal 9에서 사용되는 것을 포함하여 오늘날 사용되는 많은 인기 있는 소프트웨어 디자인 패턴의 기초입니다. Drupal 7에서 도입되었지만 광범위하게 사용되지 않았고 필요하지도 않았습니다. Drupal 9의 상황은 이제 달라졌고 널리 사용되며 필수입니다.
의존성 주입
종속성 주입은 하드 코딩된 종속성을 제거하고 런타임 또는 컴파일 타임에 변경할 수 있도록 하는 소프트웨어 디자인 패턴입니다. 종속성 주입을 추가하는 것은 쉽고 기존 코드를 방해하지 않습니다. Drupal 8은 재사용 가능한 기능을 분리하기 위해 서비스 개념을 도입했습니다. core.services.yml 은 Drupal 9의 의존성 주입의 예입니다. 우리는 이미 PHP의 Factory Pattern과 Singleton Pattern에 대해 논의했습니다.
현재 Drupal에서는 종속성 주입이 서비스에 액세스하고 사용하는 데 선호되는 방법이며 가능한 한 항상 사용해야 합니다. 전역 서비스 컨테이너를 호출하는 대신 서비스가 생성자에 인수로 전달되거나 setter 메서드를 통해 주입됩니다. 개체가 의존하는 서비스를 명시적으로 전달하는 것을 종속성 주입이라고 합니다. 여러 경우에 종속성은 클래스 생성자에서 명시적으로 전달됩니다.
Drupal core에서 사용 가능한 모든 서비스를 찾으려면 이 페이지를 확인하십시오. Drupal 문서에서 서비스에 대한 자세한 내용을 읽을 수 있습니다.
ID=1인 노드의 제목을 얻기 위한 예로 'entity_type.manager' 서비스를 생각해 보자. 사용자 지정 서비스에 삽입하려면 아래와 같이 서비스 이름을 가져와 my_module_name.services.yml 파일의 인수로 전달하면 됩니다.
my_module_name.services.yml
services: my_module_name.helper: class: Drupal\my_module_name\MyModuleHelper arguments: ['@entity_type.manager']
그런 다음 서비스 클래스에서 __construct 메서드에서 서비스를 가져와 다음과 같은 변수에 저장하기만 하면 됩니다.
MyModuleHelper.php
<?php namespace Drupal\my_module_name; use Drupal\Core\Entity\EntityTypeManagerInterface; /** * MyModuleHelper is a simple example of a Drupal 9 service. */ class MyModuleHelper { /** * The entity type manager. * * @var \Drupal\Core\Entity\EntityTypeManagerInterface */ protected $entityTypeManager; /** * Part of the DependencyInjection magic happening here. * * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager * The entity type manager. */ public function __construct(EntityTypeManagerInterface $entity_type_manager) { $this->entityTypeManager = $entity_type_manager; } /** * Returns a title for node_id = 1. */ public function getFirstNodeTitle() { $node = $this->entityTypeManager->getStorage('node')->load(1); return $node->getTitle(); } }
그런 다음 엔티티 유형 관리자 서비스를 사용하고 getFirstNodeTitle 메소드에서 nid=1인 노드의 제목을 얻을 수 있습니다.
기사를 업데이트하는 데 도움을 준 통찰력에 대해 Ankitha Shetty에게 큰 감사를 드립니다.