除非注明转载,否则本博客文章皆为原创。 MSN: wfnlxp@hotmail.com QQ: 176564452

深入浅出PHP面向对象与设计模式2

上一篇 / 下一篇  2007-10-10 10:11:12 / 个人分类:面向对象

二、生产对象的工厂--工厂方法模式

1、只会贴牌的工厂--简单工厂

如果我们的网站上有电影的介绍,同时下面有电影的bt种子,那我们可能需要看到电影页面的浏览情况和种子的下载情况(很多电影你看了介绍并不会下载,所以这两个数字是不同的)。那么我们可能会写两个类来分别获取统计的结果。

例:2_1

<?php
//电影介绍的处理类
class MovieView
{
    public function getTimes()
    {
        //返回电影介绍的浏览次数
    }
}

//电影种子下载的处理类
class MovieBtDown
{
    public function getTimes()
    {
        //返回电影种子的下载次数
    }
}

$movieView = new MovieView();
echo $movieView->geTimes();
$movieBtDown = new MovieBtDown();
$movieBtDown->getTimes();
?>

但是这样就意味着用的时候,完全要清楚在处理那个事务,也就是new哪个类的对象。

那么如果我们后面再加一个功能,统计电影被评分,我们就要再追加new语句。

而且往往看统计的都是在用户界面(UI),一般通过接收参数变量,来确定操作的是哪个功能。

其实我们需要的是把参数变量变成new语句,获得需要的对象。

这就好像一家贴牌的工厂,从进去参数(类名),出来直接就是对象,没有其他的步骤。

例:2_2

<?php
//电影介绍的处理类
class MovieView
{
    public function getTimes()
    {
        //返回电影介绍的浏览次数
    }
}

//电影种子下载的处理类
class MovieBtDown
{
    public function getTimes()
    {
        //返回电影种子的下载次数
    }
}

//电影工厂
class MovieFactory
{
    //获取电影处理类的对象,参数为类名
    public function getMovieObject($className)
    {
        return new $className;
    }
}

//获取电影工厂
$movieFactory = new MovieFactory();

//电影介绍
$what = 'MovieView';
$movieObject = $movieFactory->getMovieObject($what);
$movieObject->getTimes();

//电影种子下载
$what = 'MovieBtDown';
$movieObject = $movieFactory->getMovieObject($what);
$movieObject->getTimes();
?>

 

2、安排人员审核订单

我们为了安全,或者防止错误,希望传过来的参数是现存的类的名字,就好像订单一般需要人员来审核。

我们可以加个if,我们可以改一下MovieFactory的getMovieObject方法。

例:2_3

<?php
//电影工厂
class MovieFactory
{
    //获取电影处理类的对象,参数为类名
    public function getMovieObject($className)
    {
        if ($className==='MovieView' || $className==='MovieBtDown') {
            return new $className;
        }
    }
}

 

3、买了生产设备的新工厂--工厂方法模式

其实往往我们不光是需要得到一些对象,在new之前或之后,我们还需要执行一些行为,那么此时,简单的将参数转换成类名,就显得不太够。

这时候,也有几种处理方法,比如把这些步骤都塞进要new的类的构造方法__construct。

但是这样会使得构造方法很臃肿,而且出现了一个问题,比如下载BT种子,有些网站是要扣除积分的,但是如果是管理员下载,不应扣除积分,因为管理员要检查每个种子。

同样,上传种子的时候,可以给用户添加积分,而管理员,可以不必接受积分的处理。

这样构造方法就非常复杂,但种子的下载和上传本身是与这些工作无关的。

那么我们就难以用贴牌工厂的简单方法,我们需要生产设备了。

工厂方法模式(Factory Method):

例:2_4

<?php
//BT种子的接口
interface BT
{
    public function process();
}

//BT种子的下载处理类
class BTdown implements BT
{
    public function process()
    {
        //输出BT种子
        echo '输出BT种子';
    }
}

//BT种子的上传处理类
class BtUpload implements BT
{
    public function process()
    {
        //保存上传的BT种子
        echo '保存上传的BT种子';
    }
}

//生产BT种子处理对象的设备的接口
interface BTcreator
{
    public function createBTObject();
}

//生产BT种子下载处理对象的设备
class BTdownCreator implements BTcreator
{
    public function createBTObject()
    {
        /**
        * 如果不是管理员,送10点积分
        */
        //然后返回BT种子下载处理对象
        return new BTdown();
    }
}

//生产BT种子上传处理对象的设备
class BTUploadCreator implements BTcreator
{
    public function createBTObject()
    {
    /**
    * 如果不是管理员,送10点积分
    */
    //然后返回BT种子下载处理对象
    return new BtUpload();
    }
}

//生产BT种子处理对象的工厂
class BtFactory
{
    //获取电影处理类的对象,参数为类名
    public function getBtObject($name)
    {
        switch ($name) {
        case 'BTdown':
        $creator = new BTdownCreator();
        break;
        case 'BtUpload':
        $creator = new BtUploadCreator();
        break;
    }
    return $creator->createBTObject();
}
}

//获取bt工厂
$btFactory = new BtFactory();

//BT种子的下载处理
$what = 'BTdown';
$btObject = $btFactory->getBtObject($what);
$btObject->process();

//BT种子的上传处理
$what = 'BtUpload';
$btObject = $btFactory->getBtObject($what);
$btObject->process();
?>

上面的代码就可以看到,生产种子的处理对象时,由生产设备类来处理多余的事务,工厂本身也不受影响。

 

思考:

工厂是个不错的模式,但是很多时候,用简单的贴牌工厂就可以完成工作。

如果用工厂方法模式,那么就需要设计设备类,是否有必要用,这是需要考虑的,否则就多花了精力,但是没得到实际效果。


TAG: PHP 设计模式 面向对象 工厂方法

引用 删除 Guest   /   2008-05-25 22:28:59
www.xingchenbian33.cn
www.meinv880.cn
小人物的奋斗 引用 删除 来影   /   2007-11-24 11:44:19
3
又是一篇非常好的文章,我一直看你的教程。
有处小笔误:
class BTUploadCreator implements BTcreator
里面的注释写错了。
 

评分:0

我来说两句

显示全部

:loveliness: :handshake :victory: :funk: :time: :kiss: :call: :hug: :lol :'( :Q :L ;P :$ :P :o :@ :D :( :)

Open Toolbar