Adapter Pattern in PHP
Programming 2006/12/20 23:03Head First Design Pattern1 에서는 어댑터 패턴을 아래와 같이 정의하고 있습니다.
어댑터 패턴 (Adapter Pattern) - 한 클래스의 인터페이스를 클라이언트에서 사용하고자 하는 다른 인터페이스로 변환합니다. 어댑터를 이용하면 인터페이스의 호환성 문제 때문에 같이 쓸 수 없는 클래스들을 연결해서 쓸 수 있습니다.
디자인 패턴에 관한 책을 읽어보긴 했어도, 실제 예가 없어서인지 감이 잘 오지 않았었습니다. 이번에 devshed 에 나온 아티클2 을 읽고서 다시 패턴책을 보니 훨씬 이해가 잘 되는 것 같습니다.
어댑터 패턴은 다음과 같은 경우에 적용될 수 있습니다.
- 기존의 클래스를 확장해야 하는데, 상속을 할 수 없는 경우.
- 하나의 인터페이스를 다른 인터페이스로 변환
devshed 의 경우 첫번째 경우를 PHP 코드로 설명하고 있습니다. 먼저 추상 클래스와 이를 상속받아 구현한 클래스를 선언합니다.
abstractclass AbstractDirectoryProcessor {
private $dirPath;
abstract public function fetchDirContent();
abstract public function getDirInfo();
}
class DirectoryProcessor extends AbstractDirectoryProcessor {
public function __construct($dirPath) {
if(!is_dir($dirPath)) {
throw new Exception('Invalid directory path!');
}
$this->dirPath=$dirPath;
}
public function fetchDirContent() {
if(!$dp=opendir($this->dirPath)) {
throw new Exception('Error opening selected directory!');
}
$dircont='';
while($file=readdir($dp)) {
$dircont.=$file.'<br />';
}
fclose($dp);
return $dircont;
}
public function getDirInfo() {
$pathinfo=pathinfo($this->dirPath);
return 'Name of selected directory is '.$pathinfo['dirname'].' and its base name is the following: '.$pathinfo['basename'];
}
}
'->fetchDirContent()' 메쏘드는 해당 디렉토리에 있는 파일들의 이름을 하나씩 출력하고, '->getDirInfo()' 메쏘드는 해당 디렉토리에 대한 정보를 간단하게 출력합니다. 자, 이제 이 클래스를, 상속을 이용하지 않고 어댑터 패턴을 이용하여 기능을 확장하도록 하겠습니다.
abstract class AbstractDirectoryProcessorAdapter {
private $dirProcessor;
abstract public function getDetailedDirInfo();
}
class DirectoryProcessorAdapter extends AbstractDirectoryProcessorAdapter {
public function __construct(DirectoryProcessor $dirProcessor) {
$this->dirProcessor=$dirProcessor;
}
public function getDetailedDirInfo() {
return '<h1>Detailed information about selected directory is as follows:</h1><h2>Contents of selected directory is as follows:</h2>'.$this->dirProcessor->fetchDirContent().'<h2>Data about selected directory is as follows:</h2>'.$this->dirProcessor->getDirInfo();
}
}
트릭은 생성자에 있습니다. 어댑터의 생성자에서 어댑티 (인터페이스가 변활될 클래스) 를 자신의 속성으로 지정하여, 이후 확장된 메쏘드들에서 어댑티의 메쏘드를 사용합니다.
2.
Head First Design Pattern 의 어댑터 패턴 부분에 보면, 어댑터 패턴을 통해 기능을 확장하기 보다는 기존 클래스의 메쏘드들을 그대로 재정의하는 예제가 있습니다.
class MallardDuck {
public function quack() {
echo 'Quack';
}
public function fly() {
echo "I'm flying";
}
}
class WildTurkey {
public function gobble() {
echo 'Gobble gobble';
}
public function fly() {
echo "I'm flying a short distance";
}
}
class TurkeyAdapter {
public function __construct(WildTurkey $turkey) {
$this->turkey = $turkey;
}
public function quack() {
$this->turkey->gobble();
}
public function fly() {
for ($i=0; $i<5; $i++) {
$this->turkey->fly();
}
}
}
만약 devshed 예제 코드를 이용해서 DirectoryProcessor 를 인자로 받는 어떤 함수를 새로 정의했다고 해보겠습니다. 하지만 어떤 이유에서인지 이 함수에서는 '->getDirInfo()' 메쏘드를 사용하는 대신에 '->getSimpleDirInfo()' 라는 메쏘드를 호출합니다. 자, DirectoryProcessor 도 이미 다른 파일들에서 사용중이므로 메쏘드 이름을 바꿀 수는 없고, 함수 내용도 바꿀 수가 없습니다. 이럴때 어댑터 패턴을 사용할 수 있습니다. 어댑터 패턴에서는 간단히 '->getSimpleDirInfo()' 메쏘드를 정의하고, 이 메쏘드에서는 어댑티의 '->getDirInfo()' 를 호출해 주면 됩니다.
Head First Design Pattern 에서는, 이 외에도 유사한 패턴으로 다음 패턴들이 있다고 합니다.
- 데코레이터 패턴 - 인터페이스는 바꾸지 않고 책임(기능)만 추가
- 퍼사드 (Facade) 패턴 - 인터페이스를 간단히 바꿈
- 스토리가 있는 패턴 학습법 - Head First Design Pattern, 에릭 프리먼 외, 서환수 역, 한빛미디어, 2005 [본문으로]
- The Basics of Implementing Adapter Objects with PHP, Alejandro Gervasio [본문으로]
'Programming' 카테고리의 다른 글
| Symfony Adjacent List (0) | 2007/01/03 |
|---|---|
| AJAX Post-It 만들기 (1) | 2006/12/29 |
| Building Protein List using BeautifulSoup and BioPython (0) | 2006/12/27 |
| Symfony Form Helper - object_select_tag (0) | 2006/12/24 |
| Adapter Pattern in PHP (0) | 2006/12/20 |
| Symfony v1 beta 2 has been released (0) | 2006/12/20 |
