패턴

패턴 (Patterns)

패턴은 모범 사례와 좋은 설계를 표현하는 방법이에요. 패턴은 흔히 마주하는 프로그래밍 문제에 유연한 해결책을 보여줘요.

Factory (팩토리)

팩토리 패턴은 런타임에 객체를 만들 수 있게 해 줘요. 객체를 "만들어 내는(manufacturing)" 역할을 담당한다고 해서 Factory Pattern이라고 불러요. 파라미터화된 팩토리(Parameterized Factory)는 만들고자 하는 클래스의 이름을 인자로 받아요.

예제 #1 파라미터화된 팩토리 메서드

<?php
class Example
{
    // The parameterized factory method
    public static function factory($type)
    {
        if (include_once 'Drivers/' . $type . '.php') {
            $classname = 'Driver_' . $type;
            return new $classname;
        } else {
            throw new Exception('Driver not found');
        }
    }
}
?>

이 메서드를 클래스에 정의해 두면 드라이버를 그때그때 불러올 수 있어요. 만약 Example 클래스가 데이터베이스 추상화 클래스라면, MySQL과 SQLite 드라이버를 다음과 같이 불러올 수 있죠.

<?php
// Load a MySQL Driver
$mysql = Example::factory('MySQL');

// Load an SQLite Driver
$sqlite = Example::factory('SQLite');
?>

Singleton (싱글턴)

싱글턴은 클래스의 인스턴스가 단 하나만 존재하도록 보장하고, 그 인스턴스로 접근할 수 있는 전역 접근점을 제공해요. 싱글턴은 "GoF(Gang of Four)"의 생성(Creational) 패턴 중 하나예요.

싱글턴 패턴은 흔히 데이터베이스 클래스, 로거(logger), 프론트 컨트롤러, 요청·응답(Request/Response) 객체 같은 곳에 구현돼요.

예제 #2 싱글턴 예제

<?php
class Example
{
    private static $instance;
    private $count = 0;

    private function __construct()
    {
    }

    public static function singleton()
    {
        if (!isset(self::$instance)) {
            echo 'Creating new instance.';
            $className = __CLASS__;
            self::$instance = new $className;
        }
        return self::$instance;
    }

    public function increment()
    {
        return $this->count++;
    }

    public function __clone()
    {
        trigger_error('Clone is not allowed.', E_USER_ERROR);
    }

    public function __wakeup()
    {
        trigger_error('Unserializing is not allowed.', E_USER_ERROR);
    }
}
?>

아래 코드는 싱글턴이 어떻게 동작하는지 보여줘요.

<?php
$singleton = Example::singleton(); // prints "Creating new instance."
echo $singleton->increment(); // 0
echo $singleton->increment(); // 1

$singleton = Example::singleton(); // reuses existing instance now
echo $singleton->increment(); // 2
echo $singleton->increment(); // 3

// all of these will raise a Fatal Error
$singleton2 = new Example;
$singleton3 = clone $singleton;
$singleton4 = unserialize(serialize($singleton));
?>

Warning

싱글턴 패턴은 논란이 많은 패턴 중 하나예요. 비판하는 쪽은 싱글턴이 애플리케이션에 전역 상태(Global State)를 도입하고, 싱글턴과 그 싱글턴을 사용하는 클래스들을 강하게 결합시킨다고 주장해요. 이는 숨겨진 의존성과 예상치 못한 부작용을 만들고, 결국 테스트하고 유지보수하기 어려운 코드로 이어지죠.

나아가 PHP처럼 요청 안에서만 객체가 고유한 Shared Nothing 아키텍처라면 싱글턴을 쓸 이유가 없다고 지적하기도 해요. 요청이 시작될 때 빌더(Builder)와 팩토리 패턴으로 협력 객체 그래프를 한 번 만들어 두는 편이 더 쉽고 깔끔하죠.

싱글턴은 또 SOLID OOP 설계 원칙 몇 가지와 디미터 법칙(Law of Demeter)을 위반해요. 싱글턴은 직렬화(serialize)할 수 없고, (PHP 5.3 이전에는) 서브타입을 만들 수 없으며, 인스턴스가 싱글턴의 정적 속성으로 저장되기 때문에 가비지 컬렉션(GC)도 되지 않아요.