3

在我的应用程序中,我的模型中似乎有很多表示逻辑:

<?php foreach ($this->users as $user): ?>
    <span class="phone">
        <?php echo $user->getPhoneNumberFormattedAsText(); ?>
    </span>
<?php endforeach; ?>

起初,我开始将其视为对 View Helpers 的需求:

<span class="phone"><?php echo $this->userPhone($user->getPhone()); ?></span>

但是,我开始遇到一个问题,我有很多特定于某些模型的小视图助手,不需要占用整个文件。如果我可以将这个表示逻辑组合在一起并将其排除在模型之外,那就太好了。我认为这是装饰器模式有意义的时候。

“装饰器模式是一种允许将行为动态添加到现有对象的设计模式。”

我在网上看过一些例子,但没有真正的、实用的代码示例。我想知道你是否在你的 PHP 应用程序中成功地使用了这个模式,以及这个 PHP 示例应该是什么样子。

4

3 回答 3

2

我已经为我的 php 应用程序实现了一个装饰器模式。基本上它是一个 xml 配置文件的包装类,我在其中定义了我的基本需求。为简化起见,我以披萨为例。然后我为每种成分设置一个类,并将其包裹在另一个类中。最后,我调用了每个班级的 Prize 方法,它给了我所有内容的总和。

$order = new pizza($xml_file);
$order = new add_salami($order);
$order = new add_cheese($order);
$order = new add_tomato($order);   
$order = $order->prize();

您需要在每个成分类中维护一个指向当前对象的指针。当您调用 php new 函数时,您可以使用它来备份当前对象。它有点像(对象的)链表。然后你可以调用最后一个对象的 Prize() 方法并循环遍历所有其他类。但是要装饰你需要添加新的类。您还可以将 $xml_file 替换为起始值。我将所有装饰器类都放在一个文件中。装饰器类可以如下所示:

class add_salami {

    protected $order;
    protected $prize;

    public function __construct ($order) {
        $this->order = $order;
        $this->prize = $order->getPrize();
    }

    public function getPrize() {
        return $this->prize + 10;
    }
}

我将许多这些微小的装饰器类保存在一个巨大的文件中。

于 2012-06-27T20:12:33.057 回答
0

Zend Framework 对其表单元素使用装饰器模式。想象一下有一个 type="text" 的输​​入元素。你可以用标签、div、字段集等“装饰”这个元素。

于 2012-06-27T18:39:44.573 回答
0

我理解你的问题。是的,装饰器模式可以帮助您在甚至不同的业务逻辑中重用您的类。

我在所有可能的地方都使用装饰器模式,因为它真的可以帮助你。例如,假设您想从数据库中获取记录列表,为此您正在使用简单的存储库。这将返回您全部或一条记录。像这儿。有关存储库的更多信息,请访问此处。

$repo=new ClientRepository();
$repo->all();

但是,假设您有业务规则,在某些地方您应该记录请求的数据,而在其他地方您应该缓存请求。所以,你会怎么做。当然,大多数人会为 CacheClientRepository 和 LogClientRepository 创建单独的类。可能没问题,但是如果业务规则会同时询问您 Log 和 Cache 那么您将创建什么单独的类,例如 LogAndCacheClientReposiotry(); 如果你这样做,你最终会得到大量重复代码的类。

对于这种情况,最好的解决方案是使用 DecoratorPattern。您将需要创建一个接口并在每个装饰器中实现它。您可以随心所欲地装饰您的存储库。

这是代码示例:

 <?php

interface RepositoryInterface
{
    public function all();
}

class ClientRepository implements RepositoryInterface
{

    public function all()
    {
      // Your code for database goes here
    }
}

class CacheRepository implements RepositoryInterface
{
    /**
     * @var RepositoryInterface
     */
    private $repo;

    /**
     * CacheRepository constructor.
     * @param RepositoryInterface $repo
     */
    public function __construct(RepositoryInterface $repo)
    {
        $this->repo = $repo;
    }

    public function all()
    {
        //Code for caching goes here

        return $this->cache('cache-all',function(){
            return $this->repo->all();
        });
    }
    //......
}
class LogRepository implements RepositoryInterface
{
    /**
     * @var RepositoryInterface
     */
    private $repo;

    /**
     * LogRepository constructor.
     * @param RepositoryInterface $repo
     */
    public function __construct(RepositoryInterface $repo)
    {
        $this->repo = $repo;
    }

    public function all()
    {
        //Code for logging goes here

        return $this->log('log-all',function(){
            return $this->repo->all();
        });
    }
    //......
}

//.. Simple Repository
$repo=new ClientRepository();
//.. Cached Repository
$repo=new CacheRepository( new ClientRepository() );
//.. Logging Repository
$repo=new LogRepository( new ClientRepository() ) ;

//.. Logging and Caching at the same time
$repo=new LogRepository( new CacheRepository( new ClientRepository() ) ) ;

我希望它会对你有所帮助,因为装饰器模式是我所知道的最好的模式之一。

于 2017-11-21T10:58:36.830 回答