Design pattern/구조 패턴

[디자인 패턴] 10장 장식자 패턴

미스터로즈 2021. 5. 12. 21:37

공부하기 위해서 요약정리해놓은 것입니다..

 

정확하고 꼼꼼한 자료는 쉽게 배워 바로 써먹는 디자인 패턴을 확인하시고

코드는 github.com/infohojin/patterns 을 참고해 주세요.

 

장식자 패턴은 객체에 동적 기능을 추가하기 위해 구조를 개선하는 패턴입니다. 다양한 확장을 위해 객체를 조합합니다.

기능 추가

새로운 기능을 추가하기 위해 클래스를 확장하는 방법은 상속과 구성이 있습니다.

 

기존 객체를 확장해 새로운 기능을 추가해야 하는 경우가 있습니다. 객체지향에서는 새로운 기능을 추가하기 위해 상속을 사용합니다.

 

상속은 클래스를 확장하는 대표적인 구현 기법입니다. 하지만 상위 클래스와 하위 클래스 간에 강력한 결합 관계가 생성된다는 것입니다.

이런 강력한 결합은 유연한 확장이 어렵고, 새로운 기능을 추가할 때마다 메서드를 오버라이드하여 변경해야 합니다.

 

조건 추가

조건이란 다른 행위를 하기 위해 기존의 행위를 확장하는 것과 유사합니다.

 

상황별로 다른 행위의 동작 클래스를 설계하는 것은 쉽지 않습니다.

 

구성은 위임을 활용해 객체를 확장하는 방법입니다. 이 경우 객체를 실행하는 도중에는 동적으로 다른 객체를 결합해 확장 가능하다는 장점이 있습니다.

 

장식자 패턴은 동적으로 객체를 결합하기 위해서 객체지향의 구성을 통해 확장합니다.

 

새로운 기능을 추가할 떄는 변경이 아닌 확장을 통해 처리하는 것이 좋습니다. 확장하면 기존의 안정적인 코드 상태를 유지하면서 새로운 기능을 추가할 수 있기 때문입니다.

 

OCP의 관점에서 새로운 기능을 추가할 경우 확장을 허용하지만 기존 내용은 변경하지 못하게 합니다.

 

확장

장식자 패턴은 객체에 새로운 부가 기능을 동적으로 추가합니다. 여기서 동적은 실시간으로 변하는 객체에 새로운 행위를 추가하는 것을 의미합니다.

 

분산된 각각의 클래스는 작은 객체로 생성되며 더 큰 객체로 결합해 사용할 수 있고, 필요할 때마다 분산된 작은 객체를 결합해 새로운 객체로 생성할 수 있습니다.

즉, 장식자 패턴은 객체에 새로운 기능을 결합할 때 유용하며, 객체의 동적 조합이 많은 경우에 편리합니다.

 

장식자 패턴은 많은 종류의 작은 객체를 단일화해서 결합합니다. 분리된 객체를 조합해 새로운 파생 클래스를 생성하고 객체를 확장합니다. 단일화 결합은 객체를 실행하는 중에도 동적으로 적용할 수 있습니다.

 

 

기본 실습

장식자 패턴은 4개의 구성 요소로 이루어져 있습니다.

 

Component: 인터페이스를 정의합니다.

ConcreateComponent: 인터페이스에 정의 실제를 구현합니다.

Decorator: 컴포넌트를 참조하여 인터페이스를 일치합니다.

ConcreateDecorator: 확장 및 추가되는 기능을 작성합니다.

 

컴포넌트는 공통 기능을 정의하는 인터페이스 입니다.

<?php

/**
 * 인터페이스
 */
interface Component
{
    // 상품정보
    public function product();
    // 가격정보
    public function price();
}
<?php

class product1 implements component
{
    // 상품정보
    public function product()
    {
        return "노트북";
    }

    public function price()
    {
        // 가격을 반환합니다.
        return 20000;
    }
}

아래와 같이 클래스를 여러개 만들 수 있습니다.

 

장식자 패턴을 적용하기 위해 컴포넌트와 동일한 인터페이스를 유지하야 합니다.

<?php

abstract class Decorate implements component
{
    // 상품정보
    abstract public function product();
    
    // 가격정보
    abstract public function price();
}

 

 

인터페이스를 적용해 장식자 추상 클래스를 선언했습니다. 이제 생성한 장식자를 적용해 구체적인 객체를 확장해봅니다.

 

<?php
// ConcreateDecorator
class i7 extends Decorate
{
    public $base;
    public function __construct($concreate)
    {
        echo __CLASS__."가 생성이 되었습니다.\n";
        $this->base = $concreate;
    }

    // 상품정보
    public function product()
    {
        return $this->base->product().",i7";
    }
    
    // 가격정보
    public function price()
    {
        return $this->base->price() + 475000;
    }
}

 

<?php
// ConcreateDecorator
class ssd256 extends Decorate
{
    public $base;
    public function __construct($concreate)
    {
        echo __CLASS__."가 생성이 되었습니다.\n";
        $this->base = $concreate;
    }

    // 상품정보
    public function product()
    {
        return $this->base->product().",ssd256";
    }
    
    // 가격정보
    public function price()
    {
        return $this->base->price() + 110000;
    }
}

 

장식자 패턴은 기존의 객체에 영향을 주지 않고 새로운 기능을 동적으로 추가합니다.

 

장점

상속 형태의 확장보다 더 융통성 있게 설계할 수 있습니다. 장식자 패턴은 객체 실행 중에도 동적으로 기능을 추가할 수 있기 때문에 새로운 부가 기능을 추가하는 가장 효과적인 방법입니다.

또한 자원을 생성해 낭비하는 것이 아니라 동적으로 처리되는 시점에 자원을 할당 받습니다.

 

단점

작은 단위의 객체가 많이 생성됩니다. 유사한 성질의 작은 클래스가 증가합니다. 많은 클래스는 코드를 이해하기 어렵게 만들지만 작은 객체는 완전히 다른 클래스가 아니며 상호작용하는 방법에만 차이가 있습니다.