Magento的工厂模式

工厂模式是一个在软件设计中使用得很频繁的一设计模式,他归属创建模式。所谓工厂就是生产东西的地方,比如玩具厂生产玩具,农场生成水果/蔬菜等等。下面我们先学习或者复习一下工厂这种设计模式,我们以农场中的农民生产水果和蔬菜为例进行分析.
我们先定义一个产品抽像类,是所有产品的基类,我特地在这里加了__get/__set两个魔术方法,因为他在Magento中的Varien_Object也定义了这两个方法,这两个方法在一些框架经常使用到,如yii.这两个方法很好用,不像java了,要定义很多set/get方法。

代码块1:

abstract class Product
{
    private $_data = array();
    public function __set($var, $value){
        $this->_data[$var] = $value;
    }

    public function __get($var){
        if (isset($this->_data[$var])) {
            return $this->_data[$var];
        }
        return false;
    }
}
代码块2:水果的定义

class Fruit extends Product{
    //方法或者变量定义
}
代码块3:蔬菜的定义

class Vegetables extends Product{
    //方法或者变量定义
}
假设我们农场为了节约成本只有一个农民,而且刚开张只生产苹果和萝卜,那他又生产菜果,又生产萝卜.
菜果类:代码块2.1

class Apple extends Fruit {
    //方法或者变量定义
}
萝卜类:代码块3.1

class Radish extends Vegetables {
    //方法或者变量定义
}
代码块4:农场的定义,他的方法farmerAll相当一个农民

class Farm
{
    public static function farmerAll($productType) {
        if ('fruit' == $productType) {
            $fruit = new Apple ();
            return $fruit;
        } else if ('vegetables' == $productType) {
            $vegetables = new Radish();
            return $vegetables;
        } else {
            echo '暂不生产';
            return false;
        }
    }
}
现在来了一个客户买,他必须经过农场的农民来买,不然是就算偷菜了,呵呵。
代码如下:代码块5

$fruit = Farm::farmerAll('fruit');
$vegetables = Farm::farmerAll('vegetables');
农场发展了,决定专业化生产,一个农民生产一种产品,那么农场的定义发生变化:
代码块6:

class Farm {
    public static function farmerFruit() {
        $fruit = new Apple();
        return $fruit;
    }
    public static function farmerVegetables() {
        $vegetables = new Radish();
        return $vegetables;
    }
}
现在来了一个客户买,他找到相应的农民进行。
代码块7:

$fruit = Farm::farmerFruit();
$vegetables = Farm::farmerVegetables();
因为农场只生产菜果和萝卜,所以客户买的时候不要指明是那种水果和蔬菜,现在农场 发展了,准备再生产香蕉和白菜,类如下
香蕉类:代码块2.2

class Banana extends Fruit {
    //方法或者变量定义
}
白菜类:代码块3.2

class Cabbage extends Vegetables{
    //方法或者变量定义
}
但是为了成本考察不再追加农民.那么水果农民将生产两种水果,蔬菜农民生产两种蔬菜,此时,外界客户来买必须指定要那一种,不然农民会搞不清给那种给客户(只有一种时只能给那一种,呵呵)。此时的农场类变成了:
代码块8:

class Farm {
    public static function farmerFruit($fruitType) {
        if ('apple' == $fruitType) {
            $apple = new Apple();
            return $apple;
        }else if ('banana' == $fruitType) {
            $banana = new Banana();
            return $banana;
        }else {
            echo '暂不生产';
        return false;
        }
    }
    public static function farmerVegetables($vegetablesType) {
        if ('radish' == $vegetablesType) {
            $radish = new Radish();
            return $radish;
        }else if ('cabbage' == $vegetablesType) {
            $cabbage = new Cabbage();
            return $cabbage;
        }else {
            echo '暂不生产';
            return false;
        }
    }
}
我们已一个农场的发展,分析了工厂模式。在这个工厂模式中他有两类产品,由两个工厂方法来生产这两类产品。

XML与工厂模式

现在公司再次发展,需要再增加一个水果和蔬菜,那么我们再增加两个产品类,同时我们要修改农场中的两个工厂方法(农民),这与开闭原则是不相符的。
所以在这里我们引与xml文件,来处理这个问题。
代码块9:

<?xml version="1.0"?>
<config>
    <fruits>
        <apple >
            <file>test/apple.php</file>
        </apple>
        <banana >
            <file>test/banana.php</file>
        </bananagt>
    </fruits>
    <vegetables>
        <radish >
            <file>test/radish.php</file>
        </radish>
        <cabbage>
            <file>test/cabbage.php</file>
        </cabbagegt>
    </vegetables>
</config>
上面xml表示有两类产品下都有两个产品,其file节点表示产品类存在那个地方。如果此节点为空,则不引入。apple/banana这类节点表示类名,要把第一个字母输入为大写就可以了。现在我们来修改一下农场类.
代码块10:

class Farm {
    public static function getClassName($type) {
        //通过file_get_contents得到xml文件内容
        //通过simplexml_load_string解析xml文件
        //根据$type 找到file文件并include.
        //return 类名
    }
    public static function farmerFruit($fruitType) {
        $className = self::getClassName('fruit/' . $fruitType);
        return new $className();
    }
    public static function farmerVegetables($vegetablesType) {
        $className = self::getClassName('vegetables/' . $vegetablesType);
        return new $className();
    }
}

在这里我并没有写全getClassName,读者可以自行完成,当作一个练习。
这样当要再增加两个产品类时,我们不要修改农场类,只要在xml中加入节点就,农民就知道要生产他了。这样在没有修改源程序的情况下(当然修改了配置文件)实现了系统的扩展。同时由于类名是从getClassName统一生成的,所以以后要增强功能,也可以只修改这个方法就可以了。

在很多框架的工厂模式的应用都使用xml文件,如spring等。下面我们进入我们的Magento中是怎样应用的。

Magento工厂的应用
1、找出Magento中的产品分类。有如下几类:
Helper/model/resourceModel/block
2、Magento谁充当农场类? 由Mage.php中的Mage类充当。
3、谁充当农民?
helper的农民:由helper方法充当
model的农民:由getModel/getSingleton(单例)充当
resourceModel的农民:由getResourceModel/getResourceSingleton(单例)充当
block的农民:由getBlockSingleton(单例)充当,这个农民把生产的任务分给了Mage_Core_Model_Layout的getBlockSingleton农民.
Block还有一个农场类叫:Mage_Core_Model_Layout,里面的农民是:createBlock/getBlockSingleton.
4、xml的应用:
helper 的xml:
代码块11:

<helpers>
    <homepage>
    <class>Youthor_Homepage_Helper</class>
    </homepage>
</helpers>
取得一个helper产品对象$helper = Mage::helper(‘homepage/data’); 相当于找helper节点下的homepage节点,只不过返回的类名是class值加上data,如:Youthor_Homepage_Helper_Data(记得把data第一个字母大写),这与我们分析中的那个xml文件有一点不一样,但原理是一样的,不过这里的文件是根据类名自动引入的。如果是这样$helper = Mage::helper(‘homepage/homepage_test’),那么类名是Youthor_Homepage_Helper_Homepage_Test.由于Magento是基于Zend Frame的,所以它的类名同时表示了他的类文件所在的文件夹和类文件名,Youthor/Homepage/Helper/Homepage/Test.php有了这个规则,Magento才知道自动引入那个文件,以上的分析对model/resourceModel/block同样实用。

block的的xml:

<blocks>
    <homepage>
    <class>Youthor_Homepage_Blcok</class>
    </homepage>
</blocks>

取得一个block产品对象$block = Mage::getBlockSingleton(‘homepage/test’);

model/resourceModel的的xml:

<models>
    <homepage>
    <class>Youthor_Homepage_Model</class>
    <resourceModel>homepage_mysql4</resourceModel>
    </homepage>
    <homepage_mysql4>
    <class>Youthor_Homepage_Model_Mysql4</class>
    </homepage_mysql4>
</models>

取得一个model产品对象$model = Mage::getModel(‘homepage/test’); 取得单例model对象:$model = Mage::getSingleton(‘homepage/test’);

取得资源model,$resourceModel = Mage::getResourceModel(‘homepage/test’); 取得单例资源model对象:$resourceModel= Mage::getResourceSingleton(‘homepage/test’); 资源model的类名为Youthor_Homepage_Model_Mysql4_Test,它是从homepage找到homepage节点从而找到resourceModel节点的值homepage_mysql4,再由homepage_mysql4找到homepage_mysql4节点下的class节点的值Youthor_Homepage_Model_Mysql4再加上test(记得第一个字母大写)。

在工厂方法的第一个参数的/前的那个值 相应产品类型下的一个节点,(如homepage),在magento中一般认为是模块名,其实这不是必须的,他只是一个标示工厂方法怎样来找这个节点的名称而已,只要与你的工厂方法的第一个参数的/前的那个值相同就可以了,只不过在Magento中最好与模块名一致.

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值