专栏首页Lemon黄PHP设计模式——迭代模式

PHP设计模式——迭代模式

提供一种在不暴露对象内部逻辑的情况下顺序访问聚合对象的元素的方法。

作为商店经理,Eric的工作包括检修各个部门的产品。商店中实际上有两个部门。一个部门称为男士部门,该部门存放男性用品,另一个部门称为女士部门的女性用品。每个部门使用不同的存储结构(数据结构)存储其产品。

男士部门如下所示使用数组(array)结构存储产品:

class MenDepartment
{
    private $_products = array();
    public function  getProducts()
    {
        return $this->_products;
    }
 
    public function addProduct(Product $product)
    {
        $this->_products[] = $product;
    }
}

女士部门如下所示使用SqlStack结构存储产品:

class WomenDepartment
{
    private $_products;
 
    public function __construct()
    {
        $this->_products = new SplStack();
    }
 
    public function  getProducts()
    {
        return $this->_products;
    }
 
    public function addProduct(Product $product)
    {
        $this->_products->push($product);
    }
}

因此,对于商店经理Eric来说,检修的代码看起来就像以下一样。注意函数checkIn()

class StoreManager
{
    private $_menDepartment;
    private $_womenDepartment;
    public function __construct(MenDepartment $menDepartment, WomenDepartm
ent $womenDepartment)
    {
        $this->_menDepartment = $menDepartment;
        $this->_womenDepartment = $womenDepartment;
    }
 
    public function checkIn()
    {
       $menProducts = $this->_menDepartment->getProducts();
       foreach($menProducts as $menProduct) {
           echo $menProduct->getName();
       }
       $womenProducts = $this->_womenDepartment->getProducts();
       while (!$womenProducts->isEmpty()) {
           $womanProduct = $womenProducts->pop();
           echo $womanProduct->getName();
       }
    }
}

根据部门使用的数据结构,我们需要使用不同的方式来迭代存储。这将很快引入一个问题。想象一下,如果女士部门也决定使用数组来存储产品。我们不仅需要更新WomenDepartment类,而且还需要更改checkIn()方法。这显然违反了单一责任原则(SRP)。这是因为类(class)只有一个改变的理由。这里的checkIn()方法在很大程度上取决于两个部门使用的数据结构。至少有两个原因需要更改。

如果我们可以隐藏部门使用的存储产品的数据结构,并提供一个迭代产品的通用方法,该会怎样?这时就是我们需要迭代器模式(Iterator Pattern)的时候。

让我们重新调整代码。

首先,我们需要创建一个称为迭代器的Iterator的接口:

interface ProductIterator
{
   public function hasNext();
   public function next();
}

ProductIterator接口定义StoreManager类将用于迭代产品的两种方法。

让我们为MenDepartment类创建一个具体的迭代器:

class MenDepartmentIterator implements ProductIterator
{
   private $_position = 0;
   private $_products = array();
   public function __construct($products)
   {
        $this->_products = $products;
   }
 
   public function hasNext()
   {
        return ($this->_position < count($this->_products));
   }
   public function next()
   {
        $product = $this->_products[$this->_position];
        $this->_position ++;
        return $product;
   }
}

我们在MenDepartment中需要一个内部指针来跟踪当前索引。

同理,我们也为WomenDepartment类创建一个具体的迭代器:

class WomenDepartmentIterator implements ProductIterator
{
   private $_products ;
   public function __construct($products)
   {
        $this->_products = $products;
   }
 
   public function hasNext()
   {
        return !($this->_products->isEmpty());
   }
 
   public function next()
   {
        $product = $this->_products->pop();
        return $product;
   }
}

现在,我们需要为MenDepartmentWomenDepartment创建一个新方法(createIterator)。该方法的作用是实例化先前设计的具体迭代器。这样我们就可以直接获得其迭代器:

class MenDepartment
{
    private $_products = array();
    public function  getProducts()
    {
        return $this->_products;
    }
 
    public function addProduct(Product $product)
    {
        $this->_products[] = $product;
    }
 
    public function createIterator()
    {
        return new MenDepartmentIterator($this->_products);
    }
}

class WomenDepartment
{
    private $_products;
    public function __construct()
    {
        $this->_products = new SplStack();
    }
 
    public function  getProducts()
    {
        return $this->_products;
    }
 
    public function addProduct(Product $product)
    {
        $this->_products->push($product);
    }
 
    public function createIterator()
    {
        return new WomenDepartmentIterator($this->_products);
    }
}

最后,让我们看看StoreManager的变化。其余的都保持不变,我们唯一需要更改的地方是checkIn()方法,我们还需要添加一个便捷方法checkInByIterator()以使代码更简洁:

class StoreManager
{
    private $_menDepartment;
    private $_womenDepartment;
 
    public function __construct(MenDepartment $menDepartment, WomenDepartment $womenDepartment)
    {
        $this->_menDepartment = $menDepartment;
        $this->_womenDepartment = $womenDepartment;
    }
 
    public function checkIn()
    {
        $menDepartmentIterator   = $this->_menDepartment->createIterator();
        $womenDepartmentIterator = $this->_womenDepartment->createIterator();
        $this->checkInByIterator($menDepartmentIterator);
        $this->checkInByIterator($womenDepartmentIterator);
    }
 
    public function checkInByIterator(ProductIterator $productIterator)
    {
        while ($productIterator->hasNext()) {
            $product = $productIterator->next();
            echo $product->getName();
        }
    }
}

正如我们最后所看到的,StoreManager具有抗脆弱性。它与部门用于存储产品的数据结构无关。该代码现在更易于维护。

在我们的示例中,迭代器模式提供了一种顺序访问聚合对象(MenDepartmentWomenDepartment对象)的元素(产品)的方法,而无需暴露其内部逻辑表现形式(ArraySqlStack)。

本文分享自微信公众号 - Lemon黄(lemonhunag),作者:Lemon黄

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2019-11-11

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • PHP设计模式——模板方法

    管理公司员工的日常行程可能是一项耗时的工作。如果可以使用程序将日常任务编程为自动发生,那将容易得多。Mark在Yahaa Inc工作了四年, 他是一名程序员,他...

    Lemon黄
  • PHP设计模式——抽象方法

    Dragon公司的业务受到轰炸,而CEO希望特许所有海外分支机构的专营权。他首先要注意的问题是如何确保产品质量。他们不希望特许经营者削减成本和使用低质量的组件。...

    Lemon黄
  • 通俗易懂PHP基础【9-类和对象(1)】

    曾经见过一个摄影师喂藏羚羊喝水,同行的警察把藏羚羊赶走了,摄影师问为什么,警察说,要不然它会以为人类是善良的。

    Lemon黄
  • PHP设计模式之装饰器(装饰者)模式(Decorator)入门与应用详解

    本文实例讲述了PHP设计模式之装饰器(装饰者)模式(Decorator)入门与应用。分享给大家供大家参考,具体如下:

    砸漏
  • PHP设计模式之组合模式

    互联网公司流行扁平化管理,也就是管理层级尽量少于或者不超过三层,作为一个底层的码农,你的CEO和你的职级也就相差3层以内。但是很多传统企业,则会有非常深的层级关...

    硬核项目经理
  • 我也能写数据库 —— 单表查询

    在翻译关系代数这篇文档的时候,总有一种惴惴不安的感觉伴随着我,其实还是对之前概览的一知半解,而DEMO项目Calcite-example-CSV为了介绍特性,添...

    麒思妙想
  • Application Firewall Design

    Application Firewall Design Web Application Firewall, 7layer Firewall ---- 目录 1....

    netkiller old
  • Flutter基础widgets教程-Placeholder篇

    青年码农
  • PHP设计模式之外观模式(Facade)入门与应用详解

    本文实例讲述了PHP设计模式之外观模式(Facade)入门与应用。分享给大家供大家参考,具体如下:

    砸漏
  • JS高级-数据结构的封装

    最近在看了《数据结构与算法JavaScript描述》这本书,对大学里学的数据结构做了一次复习(其实差不多忘干净了,哈哈)。如果能将这些知识捡起来,融入到实际工作...

    小古哥

扫码关注云+社区

领取腾讯云代金券