PHP 8의 디자인 패턴: 팩토리 방식

안녕!
이 기사에서는 예제와 함께 Factory Method 디자인 패턴을 사용하는 방법을 보여줍니다.

장바구니 클래스가 있고 해당 클래스에 장바구니를 캐싱하고 오랫동안 유지하기 위한 메서드가 포함되어 있다고 가정해 보겠습니다. RedisDB에 캐시하고 MySQL에 저장하는 것이 좋습니다.

class CartModel
{
    public array $data;
    // Better take this settings from special file or env variables
    // but this article not about storing settings
    private array $redisSettings = [
        'user' => 'test_user',
        'password' => 'password'
    ];
    private array $mysqlSettings = [
        'hostname' => 'localhost',
        'login' => 'test_user',
        'password' => 'secret',
        'database' => 'test_db'
    ];

    // We need to implement a cache storage method
    // the Redis DB is better suited for this
    public function cache(): void
    {
    }

    public function save(): void
    {
    }
}


여기에 빈 클래스가 있습니다. 이제 이러한 메서드를 구현해야 합니다. 사실 각각의 의미는 원하는 데이터베이스에 연결하고 바구니에 대한 데이터를 저장하는 것입니다. Factory Method 패턴 덕분에 데이터베이스로 작업하는 모든 클래스의 공통 코드(저장)를 추상 클래스로 옮길 것입니다. 그리고 연결과 관련된 기능은 각 데이터베이스마다 다를 것이므로 공통 인터페이스를 사용하여 별도로 꺼낼 것입니다.

abstract class AbstractDataBaseFactory
{
    // A directly factory method that allows subclasses to return
    // any concrete connectors of the desired interface, since it is made abstract
    // We will create the interface a little later
    abstract public function getDataBase(): DataBaseConnector;

    // And this method will be the same for all databases
    public function save(array $data): void
    {
        $database = $this->getDataBase();
        $database->connect();
        $database->save($data);
        $database->disconnect();
    }
}


RedisDB에 대한 구체적인 클래스를 구현해 봅시다.

class RedisFactory extends AbstractDataBaseFactory
{
    // php8 allows you to add private login and password fields using the constructor
    public function __construct(private readonly string $login, private readonly string $password)
    {}

    // Concrete Factory Method Implementation
    // Returns an instance of the connector class that implements the DataBaseConnector interface
    public function getDataBase(): DataBaseConnector
    {
        return new RedisConnector($this->login, $this->password);
    }
}


거의 같은 방식으로 Mysql 데이터베이스용 클래스를 생성합니다.

class MysqlFactory extends AbstractDataBaseFactory
{
    // Unlike Redis, we will need an array of data to connect
    public function __construct(private readonly array $settings)
    {}

    // Concrete Factory Method Implementation
    public function getDataBase(): DataBaseConnector
    {
        return new MysqlConnection($this->settings);
    }
}


바구니가 작동하는 것은 방금 만든 이러한 데이터베이스 클래스와 함께입니다.

그러나 커넥터의 인터페이스와 커넥터는 아직 작성되지 않았습니다. 이 누락을 수정합시다. 데이터베이스에 연결하고, 연결을 끊고, 물론 데이터를 저장하는 방법이 필요합니다. 앞으로 다양한 방식으로 인터페이스를 확장할 수 있겠지만 현재로서는 이 정도면 충분하다.

interface DataBaseConnector
{
    public function connect();
    public function disconnect();
    public function save(array $data): void;
}


RedisDB 및 Mysql 커넥터의 구현에 대해서는 설명하지 않겠습니다. 모든 것이 상당히 표준적으로 구현될 수 있습니다.

class RedisConnector implements DataBaseConnector
{
    public function __construct(private $login, private $password)
    {}

    /**
     * @throws Exception
     */
    public function connect(): void
    {
        // connect() method implementation
    }

    public function disconnect()
    {
        // disconnect() method implementation
    }

    public function save(array $data): void
    {
        // save() method implementation
    }
}



class MysqlConnection implements DataBaseConnector
{
    public function __construct(private $settings)
    {}

    public function connect()
    {
        // connect() method implementation
    }

    public function disconnect()
    {
        // disconnect() method implementation
    }

    public function save(array $data): void
    {
        // save() method implementation
    }
}


모든 것이 카트 방식에서 사용될 준비가 되었습니다.

class CartModel
{
    //...

    public function cache(): void
    {
        try {
            $redis = new RedisFactory($this->redisSettings['user'], $this->redisSettings['password']);
            $redis->save($this->data);
        } catch (\Exception $e) {
            //...
        }
    }

    public function save(): void
    {
        try {
            $mysql = new MysqlFactory($this->mysqlSettings);
            $mysql->save($this->data);
        } catch (\Exception $e) {
            //...
        }
    }
}


Factory Method 패턴의 사용 덕분에 연결, 저장, 데이터 형식, 연결 해제 등 세부 작업에 대한 걱정 없이 쇼핑 카트와 같은 모델 내부의 다양한 데이터베이스에 액세스할 수 있습니다. 코드 중복, 과도한 부하를 방지합니다. 방법 및 클래스, 신성한 클래스 생성.


© 사진: Patrick Hendry on Unsplash

좋은 웹페이지 즐겨찾기