PHP设计模式(八)装饰器模式Decorator实例详解【结构型】

下面是针对“PHP设计模式(八)装饰器模式Decorator实例详解【结构型】”文章的完整攻略。

1. 什么是装饰器模式Decorator?

装饰器模式(Decorator)是一种结构型设计模式,它允许你动态地将对象添加到现有对象中。使用装饰器模式,可以将一个或多个装饰器包装在对象上,从而改变其行为。当需要动态地将对象添加到现有对象中或从对象中删除对象时,可以使用装饰器模式。

2. 装饰器模式的主要组成部分

装饰器模式包含以下组成部分:

  • 抽象组件(Component):定义了一个抽象类,它是被装饰对象和所有具体装饰器的超类,提供了被装饰对象的基本行为,这些基本行为可以由具体装饰器来扩展。
  • 具体组件(ConcreteComponent):实现抽象组件类的具体类,提供基本行为。
  • 抽象装饰器(Decorator):定义了一个抽象类来装饰抽象组件或其具体子类,它可以是一个具体的类或一个抽象类。
  • 具体装饰器(ConcreteDecorator):实现抽象装饰器类的具体类,可以为装饰对象添加新的行为或扩展现有行为。

3. 装饰器模式的实例说明

下面我们通过两个具体的示例说明装饰器模式的使用。

示例1:制作不同口味的咖啡

假设我们正在制作咖啡并需要为其添加不同的口味:白糖、红糖和牛奶。在这个例子中,咖啡是抽象组件,而白糖、红糖和牛奶是具体装饰器。

首先,我们定义抽象组件:

    abstract class Coffee {
        protected $description = "Unknown Coffee";

        public function getDescription() {
            return $this->description;
        }

        public abstract function cost();
    }

接下来,我们定义具体组件:

    class Espresso extends Coffee {
        public function __construct() {
            $this->description = "Espresso";
        }

        public function cost() {
            return 1.99;
        }
    }

然后,我们定义抽象装饰器:

    abstract class CoffeeDecorator extends Coffee {
        public abstract function getDescription();
    }

接下来,我们定义具体装饰器:

    class Milk extends CoffeeDecorator {
        protected $coffee;

        public function __construct(Coffee $coffee) {
            $this->coffee = $coffee;
        }

        public function getDescription() {
            return $this->coffee->getDescription() . ", Milk";
        }

        public function cost() {
            return $this->coffee->cost() + 0.20;
        }
    }

    class Sugar extends CoffeeDecorator {
        protected $coffee;

        public function __construct(Coffee $coffee) {
            $this->coffee = $coffee;
        }

        public function getDescription() {
            return $this->coffee->getDescription() . ", Sugar";
        }

        public function cost() {
            return $this->coffee->cost() + 0.10;
        }
    }

    class RedSugar extends CoffeeDecorator {
        protected $coffee;

        public function __construct(Coffee $coffee) {
            $this->coffee = $coffee;
        }

        public function getDescription() {
            return $this->coffee->getDescription() . ", RedSugar";
        }

        public function cost() {
            return $this->coffee->cost() + 0.15;
        }
    }

我们现在可以创建具体的咖啡对象,并动态地为其添加不同的装饰器:

    $beverage = new Espresso();
    echo $beverage->getDescription() . " $" . $beverage->cost();

    $beverage = new Milk($beverage);
    echo $beverage->getDescription() . " $" . $beverage-> cost();

    $beverage = new RedSugar($beverage);
    echo $beverage->getDescription() . " $" . $beverage->cost();

    $beverage = new Sugar($beverage);
    echo $beverage->getDescription() . " $" . $beverage->cost();

当我们执行这段代码时,输出结果如下:

    Espresso $1.99
    Espresso, Milk $2.19
    Espresso, Milk, RedSugar $2.34
    Espresso, Milk, RedSugar, Sugar $2.44

这说明我们成功地为咖啡添加了不同的口味。

示例2:动态添加属性到HTML标签

接下来,我们通过另一个示例来说明装饰器模式。假设我们需要动态地向HTML标签添加不同的属性,如class、id、style等。在此示例中,HTML标签是抽象组件,而属性是具体装饰器。

首先,我们定义抽象组件:

    abstract class HtmlTag {
        private $name;
        private $attributes;
        private $value;

        public function __construct($name) {
            $this->name = $name;
            $this->attributes = array();
            $this->value = "";
        }

        public function getName() {
            return $this->name;
        }

        public function setAttribute($attribute, $value) {
            $this->attributes[$attribute] = $value;
        }

        public function removeAttribute($attribute) {
            unset($this->attributes[$attribute]);
        }

        public function setValue($value) {
            $this->value = $value;
        }

        public function getValue() {
            return $this->value;
        }

        public function getAttributes() {
            return $this->attributes;
        }

        public abstract function render();
    }

接下来,我们定义具体组件:

    class HtmlInput extends HtmlTag {
        public function __construct($name) {
            parent::__construct($name);
        }

        public function render() {
            $html = "<input type=\"text\" name=\"{$this->getName()}\" value=\"{$this->getValue()}\" ";

            $attributes = $this->getAttributes();
            foreach($attributes as $attribute => $value) {
                $html .= "{$attribute}=\"{$value}\" ";
            }

            $html .= " />";

            return $html;
        }
    }

然后,我们定义具体装饰器:

    class HtmlClass extends HtmlTag {
        private $component;
        private $class;

        public function __construct(HtmlTag $component, $class) {
            $this->component = $component;
            $this->class = $class;
        }

        public function render() {
            $attributes = $this->component->getAttributes();
            $attributes['class'] = $this->class;
            $this->component->setAttributes($attributes);

            return $this->component->render();
        }
    }

    class HtmlId extends HtmlTag {
        private $component;
        private $id;

        public function __construct(HtmlTag $component, $id) {
            $this->component = $component;
            $this->id = $id;
        }

        public function render() {
            $attributes = $this->component->getAttributes();
            $attributes['id'] = $this->id;
            $this->component->setAttributes($attributes);

            return $this->component->render();
        }
    }

我们现在可以创建具体的HTML对象,并动态地为其添加不同的属性:

    $input = new HtmlInput("username");
    $input->setValue("admin");

    $input = new HtmlClass($input, "form-control");
    $input = new HtmlId($input, "username");

    echo $input->render();

当我们执行这段代码时,输出结果如下:

    <input type="text" name="username" value="admin" class="form-control" id="username"  />

这说明我们成功地为HTML标签动态添加了不同的属性。

4. 总结

本文通过以上两个示例详细讲解了装饰器模式的使用。要使用装饰器模式,需要遵循一些结构规则,并且需要理解抽象组件和装饰器之间的关系。如果需要动态地扩展一个对象,并且不能直接修改它的代码,那么应该考虑使用装饰器模式。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:PHP设计模式(八)装饰器模式Decorator实例详解【结构型】 - Python技术站

(0)
上一篇 2023年6月26日
下一篇 2023年6月26日

相关文章

  • java栈实现二叉树的非递归遍历的示例代码

    让我们来详细讲解一下“Java栈实现二叉树的非递归遍历的示例代码”的完整攻略。 什么是非递归遍历? 在讲解“Java栈实现二叉树的非递归遍历的示例代码”之前,我们先来了解一下什么是非递归遍历。 二叉树的遍历有三种方式: 前序遍历:根节点 → 左子树 → 右子树。 中序遍历:左子树 → 根节点 → 右子树。 后序遍历:左子树 → 右子树 → 根节点。 在使用递…

    other 2023年6月27日
    00
  • Win11“开始”菜单中如何显示/隐藏最常用的应用程序?

    “Win11”开始菜单可以根据用户的使用习惯,自动显示/隐藏最常使用的应用程序。下面是显示/隐藏最常使用应用程序的方法: 点击“Win11”开始菜单,此时开始菜单会显示一列最常用的应用程序 如果想要将一个应用程序从最常使用的应用程序列表中隐藏,可以右键点击该应用程序,然后选择“从此列表移除” 如果想要将一个应用程序重新显示在最常使用的应用程序列表中,可以打开…

    other 2023年6月25日
    00
  • cpu是什么?

    CPU是什么? CPU(Central Processing Unit,中央处理器)是计算机中的一个重要组件,它是计算机执行指令和处理数据的核心部件,相当于计算机的“大脑”。 CPU主要有两个基本部分:控制单元(Control Unit)和算术逻辑单元(Arithmetic Logic Unit,ALU)。控制单元用于控制指令的执行流程,包括指令的获取、解析…

    其他 2023年4月16日
    00
  • PHP 关于访问控制的和运算符优先级介绍

    PHP是一种极其流行的后端语言,对于开发者来说掌握PHP的访问控制和运算符优先级非常重要。下面我将为大家详细介绍这两个方面的内容。 PHP访问控制 PHP 有三种访问控制修饰符,它们分别是:public、protected 和 private。 public 当变量或方法被声明为 public 时,它们可以从任何地方进行访问。下面是一个示例: class C…

    other 2023年6月27日
    00
  • 易语言调用api枚举网卡名称并且获取信息的代码

    下面是关于“易语言调用API枚举网卡名称并获取信息”的完整攻略。 1. 前提知识 在进行本操作之前,需要了解以下内容: 理解API函数调用的基本原理、参数类型和返回值类型。 理解Windows系统中的网络配置和网卡信息。 掌握基本的Windows网络编程知识。 2. 调用API枚举网卡名称并获取信息 2.1 获取网卡列表 在Windows系统中,我们可以使用…

    other 2023年6月20日
    00
  • QT6中QTextcodec头文件找不到的解决方法

    当我们在使用QT6进行开发时,有时候会出现“QTextcodec头文件找不到”的错误提示,这是因为QT6中已经不再支持QTextcodec。在这种情况下,我们可以采用以下两种方法来解决这个问题: 方法一:使用QTextCodec替代QTextcodec QTextcodec在QT6中已经被弃用,取而代之的是QTextCodec(注意大小写)。因此,我们可以通…

    other 2023年6月27日
    00
  • mysql修改语句(数据)

    当然,我很乐意为您提供有关“MySQL修改语句(数据)”的完整攻略。以下是详细的步骤和两个示例: 1 修改数据 在MySQL中,可以使用UPDATE语句修改表中的数据。UPDATE语句将更新指定表中的一行或多行数据。 2 示例 以下是两个修改数据的示例: 2.1 修改单个行 要修改单个行,可以使用以下语法: UPDATE table_name SET col…

    other 2023年5月6日
    00
  • 用html制作日历表

    用HTML制作日历表 HTML是一种非常流行的网页制作语言,除了可以编写网页的文本内容,还可以利用HTML标签来设计网页结构、排版和样式。其中,制作日历表是一个非常有趣的HTML项目,不仅可以丰富网页的内容,也可以提高网页设计的能力。 制作一个简单的日历表 首先,我们来看一下如何利用HTML标签制作一个简单的日历表。 示例代码如下: <table&gt…

    其他 2023年3月28日
    00
合作推广
合作推广
分享本页
返回顶部