我的应用程序中有一点我的模型中似乎有很多表示逻辑:
<?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>
然而,我已经开始遇到一个问题,我有很多特定于某些模型的View Helper,不需要占用整个文件。如果我可以将这个表示逻辑组合在一起并将其保持在模型之外,那将是很好的。我认为这是decorator pattern有意义的时候。
“装饰器模式是一种设计模式,允许动态地将行为添加到现有对象。”
我在网上看到了一些例子,但没有真实,实用的代码示例。我想知道你是否已经在PHP应用程序中成功使用了这个模式,以及它的PHP示例应该是什么样的。
答案 0 :(得分:2)
我为我的php应用程序实现了一个装饰器模式。基本上它是xml配置文件的包装类,我在其中定义了我的基本需求。为了简化,我以披萨为例。然后我为每种成分都有一个类,并将它包装在另一个类中。最后,我称每个班级的奖励方法,它给了我所有的总和。
$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;
}
}
我把很多这些小装饰器类放在一个巨大的文件中。
答案 1 :(得分:0)
Zend Framework使用装饰器模式作为其表单元素。想象一下,输入元素的类型为“text”。您可以使用标签,div,字段集等“装饰”此元素。
答案 2 :(得分:0)
我理解你的问题。是的,Decorator模式可以帮助您在不同的业务逻辑中重用您的类。
我随处可见装饰模式,因为它可以真正帮助你。例如,假设您想从数据库获取记录列表,为此您使用简单的存储库。这将返回你所有或一个记录。像这儿。有关存储库的更多信息,请访问此处。
$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() ) ) ;
我希望它会对你有所帮助,因为装饰模式是我所知道的最佳模式之一。