2025-04-14

当一个对象或者数据有多种展示方式的时候用装饰者模式.  比如数组可以以json, xml的展示方式. 再比如用户数据A页面会有一种展示方式. B页面会有一种展示方式

 

数组装饰

现在来用装饰者模式展示array. 先定义一个对象用来接受数组和输出输出.

class OutputData {

    private DecoratorInterface $decorator;

    public function __construct(private array $data) {}

    public function setDecorator(DecoratorInterface $decorator) {
        $this->decorator = $decorator;
    }

    public function output() {
        return $this->decorator->renderData($this->data);
    }

}

 

定义装饰者, 分别定义JSON和XML

 

interface DecoratorInterface {
    public function renderData($data);
}

class XMLRender implements DecoratorInterface {
    function toXml(SimpleXMLElement $object, array $data) {
        foreach ($data as $key => $value) {
            // if the key is an integer, it needs text with it to actually work.
            $valid_key  = is_numeric($key) ? "key_$key" : $key;
            $new_object = $object->addChild(
                $valid_key,
                is_array($value) ? null : htmlspecialchars($value)
            );

            if (is_array($value)) {
                $this->toXml($new_object, $value);
            }
        }
    }
    public function renderData($data) {
        $xml = new SimpleXMLElement('<root/>');
        $this->toXml($xml, $data);
        return $xml->saveXML();
    }
}

class JsonRender implements DecoratorInterface {
    public function renderData($data) {
        return json_encode($data);
    }
}

 

最后根据所需输出指定类型

$data = new OutputArray([
    'books' => [
        'Abook',
        'Bbook',
        'Cbook'
    ],
    'cart' => [
        'Acart',
        'Bcart',
        'Ccart'
    ]
]);
$data->setDecorator(new XMLRender());
$data->setDecorator(new JsonRender());
print_r($data->output());

 

商品装饰

定义菜品接口

interface FoodItem {
    // 定义附加的成本.
    public function cost();
}

 

// 定义一个手抓饼. 成本为10块钱.
class HandCake implements FoodItem {
    private array  $items = [];
    public function cost() {
        return 10;
    }

    public function addItem(FoodItem $item) {
        $this->items[] = $item;
    }

    public function Calculation() {
        $total = $this->cost();
        foreach ($this->items as $item) {
            $total += $item->cost();
        }
        return $total;
    }
}

 

定义小菜可选增加

// 定义鸡蛋小菜的成品为4块
class Egg implements FoodItem {
    public function cost () {
        return 4;
    }
}

// 定义一个火腿价格为6块
class Ham implements FoodItem {
    public function cost () {
        return 6;
    }
}

$handcake = new HandCake();
$handcake->addItem(new Egg());
$handcake->addItem(new Egg());
$handcake->addItem(new Egg());
$handcake->addItem(new Ham());
$handcake->addItem(new Ham());
print $handcake->Calculation();

产品活动装饰

定义一个商品类

class Product {
    public string $title;
    public float $price;
}

定义活动接口

interface ProductActivities {
    public function getReduce(Product $product);
}

定义活动

// 双十一减5块.
class Two11 implements ProductActivities {
    public function getReduce($product) {
        return 5;
    }
}

// 满500减50.
class Filled500 implements ProductActivities {
    public function getReduce(Product $product) {
        if ($product->price > 500) {
            return 50;
        }
    }
}

 

定义产品建造者来获取产品

class ProductBuilder {
    private Product $product;
    private array $activities;

    public function __construct($title, $price) {
        $product = new Product();
        $product->title = $title;
        $product->price = $price;
        $this->product = $product;
    }

    /**
     * 获取商品.
     *
     * @return mixed
     */
    public function getProduct() {
        // 根据活动重新计算减少的价格.
        $price = $this->product->price;
        foreach ($this->activities as $activity) {
            $price -= (int)$activity->getReduce($this->product);
        }
        $this->product->price = $price;
        return $this->product;
    }

    /**
     * 添加活动.
     *
     * @param $activity
     */
    public function addActivity($activity) {
        $this->activities[] = $activity;
    }
}

最后测试

$product = new ProductBuilder('Iphone16', '9000');
$product->addActivity(new Two11());
$product->addActivity(new Filled500());
print_r($product->getProduct());

 

标签: 设计模式