Decorator 裝飾者(包裝器)模式-極簡範例

單一元件的 Decorator 模式
這個範例是一個基本網站,想要在不更動原先功能的情況下,擴充其它功能

abstract class IComponent
{
    protected $site;
    abstract public function getSite();
    abstract public function getPrice();
}

//抽象類別繼承抽象類別
abstract class Decorator extends IComponent
{
    //由於是極簡範例,所以這個抽象類的工作是保持對 Component 的參考
}

基本的網站

class BasicSite extends IComponent
{
    public function __construct()
    {
        $this->site = "Basic Site (1200)";
    }
    
    public function getSite()
    {
        return $this->site;
    }
    
    public function getPrice()
    {
        return 1200;
    }
}

第 1 個擴充功能

//注意這裡繼承的是Decorator而不是IComponent,但結果都是一樣的
class Maintenance extends Decorator
{
    public function __construct(IComponent $siteNow)
    {
        $this->site = $siteNow;
    }
    
    public function getSite()
    {
        $fmat = "<br />&nbsp;&nbsp; Maintenance (950)";
        return $this->site->getSite().$fmat;
    }
    
    public function getPrice()
    {
        return 950 + $this->site->getPrice();
    }
}

第 2 個擴充功能

class Video extends IComponent
{
    public function __construct(IComponent $siteNow)
    {
        $this->site = $siteNow;
    }
    
    public function getSite()
    {
        $fmat = "<br />&nbsp;&nbsp; Video (350)";
        return $this->site->getSite().$fmat;
    }
    
    public function getPrice()
    {
        return 350 + $this->site->getPrice();
    }
}

第 3 個擴充功能

class DataBase extends Decorator
{
    public function __construct(IComponent $siteNow)
    {
        $this->site = $siteNow;
    }
    
    public function getSite()
    {
        $fmat = "<br />&nbsp;&nbsp; MySQL Database (800)";
        return $this->site->getSite().$fmat;
    }
    
    public function getPrice()
    {
        return 800 + $this->site->getPrice();
    }
}

客戶端程式,注意透過方法 wrapComponent() 裝飾包裝

class Client
{
    private $basicSite;
    
    public function __construct()
    {
        $this->basicSite = new BasicSite();
        $this->basicSite = $this->wrapComponent($this->basicSite);
        
        $siteShow = $this->basicSite->getSite();
        $format = "<br />&nbsp;&nbsp;<strong>Total= $";
        $price = $this->basicSite->getPrice();
        
        echo $siteShow.$format.$price."</strong></p>";
    }
    
    private function wrapComponent(IComponent $component)
    {
        $component = new Maintenance($component);
        $component = new Video($component);
        $component = new DataBase($component);
        return $component;
    }
}

$worker = new Client();

Browser結果
Basic Site (1200)
Maintenance (950)
Video (350)
MySQL Database (800)
Total= $3300