需求分析

  1. 假设一个网站有文章(a),帖子(t),产品(g),专题(s)四种类型的内容
  2. 设计一种收藏夹,用户可以列出所有的收藏,指定类型的收藏,进行一些分类和搜索
  3. 最少的数据冗余

设计分析

      具备多种数据类型,就表示多种类型的数据不同,显示方式不同,搜索方式不同;因此,我们不考虑类型的数据结构,只考虑收藏夹的数据结构,设计一种仅有关联的无冗余系统;类型数据的获取及显示采用接口的方式。

数据设计方案

      id(编号)   uid(用户编号)    type(收藏类型)   rid(关联编号)    params(收藏参数[可无])

程序设计

  1. 建一个通用接口,负责本类型的数据调用,以及展示模板的调用
  2. 接口返回不同的数据,如文章只返回标题和地址,帖子返回发帖人,产品返回价格和专题返回创建时间等

设计的优点

  1. 最小冗余数据
  2. 任意扩展类型
  3. 不同类型返回任意不同的数据结构
  4. 不同类型定义不同的显示方式

关键代码

定义一个单例调用入口:

<?php
include dirname(__FILE__).'/storage/base.php';//调用基本模型类
class Favorite{
    private static $_instance=array();
    private function __construct(){}//单例
    //获取模型实例
    public static function getInstance($type){
        //存在时直接返回
        if(isset(self::$_instance[$type])){
            return self::$_instance[$type];
        }
        //包含并实例化
        $file=dirname(__FILE__).'/storage/'.$type.'.php';
        if(is_file($file)){
            include $file;
            $calss='FavoriteStorage'.ucfirst(trim($type));
            self::$_instance[$type]=new $calss();
        }else{
            //不存在模型返回基本模型
            self::$_instance[$type]=new FavoriteStorageBase();
        }
        return self::$_instance[$type];
    }
    //获取模型仓库列表
    public static function getStores(){
        $connectors = array();
        $iterator = new DirectoryIterator(__DIR__.'/storage');
        foreach ($iterator as $file){
            $fileName = $file->getFilename();
            if(!$file->isFile() || $file->getExtension()!='php'){
                continue;
            }
            $connectors[] = str_ireplace('.php', '', $fileName);
        }
        return $connectors;
    }
}

定义一个基本的模型类:

<?php
class FavoriteStorageBase{
    public function getItem($id){
        return false;
    }
    public function getItems($ids){
        return false;
    }
    public function geItemShow($row){
        return false;
    }
    public function geItemsShow($rows){
        $return=false;
        foreach($rows as $i=>$row){
            $return[$i]=geItemShow($row);
        }
        return $return;
    }
}

定义文章模型类:

<?php
class FavoriteStorageArticle extends FavoriteStorageBase{
    public function getItem($id){
        return array('title'=>'文章标题','url'=>'文章地址');
    }
    public function getItems($ids){
        return array(
            '1'=>array('title'=>'文章标题1','url'=>'文章地址1'),
            '2'=>array('title'=>'文章标题2','url'=>'文章地址2'),
        );
    }
    public function geItemShow($row){
        if(!is_array($row)){
            $row=$this->getItem($row);
        }
        return "文章:<a href='{$row['url']}'>{$row['title']}</a>";
    }
}

定义商品模型类:

<?php
class FavoriteStorageGood extends FavoriteStorageBase{
    public function getItem($id){
        return array('title'=>'商品名称','url'=>'商品地址','price'=>'10.00');
    }
    public function getItems($ids){
        return array(
            '2'=>array('title'=>'商品名称2','url'=>'商品地址2','price'=>'20.00'),
        );
    }
    public function geItemShow($row){
        if(!is_array($row)){
            $row=$this->getItem($row);
        }
        return "商品:<a href='{$row['url']}'>{$row['title']} ({$row['price']})</a>";
    }
}

页面调用示例:

<?php
 
include JPATH_COMPONENT.'/core/favorite.php';
var_dump(Favorite::getStores()); 
 
/**************单个调用使用**************/
foreach($this->items as $item){
    $item=(array)$item;
    $model=Favorite::getInstance($item['type']);
    $row=$model->getItem($item['rid']);
    echo $model->geItemShow($row).'<br />';
}
 
echo '<hr>';
 
/**************多个调用使用**************/
 
foreach($this->items as $item){
    $item=(array)$item;
    $types[$item['type']][]=$item['id'];
}
 
foreach($types as $type=>$ids){
    $models[$type]=Favorite::getInstance($type);
    $rows[$type]=$models[$type]->getItems($ids);
}
 
foreach($this->items as $item){
    $item=(array)$item;
    echo $models[$item['type']]->geItemShow($rows[$item['type']][$item['rid']]).'<br />';
}

注:上面的没有写搜索的方法,只需要在基类中定义一个搜索的方法和在子类中重构即可。