Magento设计模式

34

在我看来,Magento代表了一个建立在深思熟虑的编码原则之上的PHP系统 - 其中可重用的设计模式是其中之一。从PHP系统的角度来看,我认为它可以被认为是相当前沿的,因此从架构的角度考虑是值得考虑的。

据我所知,有许多设计模式可供面向对象的开发人员使用。在像Magento这样的开源系统中看到这些模式被应用,使得开发人员可以查看这些模式的实际使用情况而不是仅仅在有些时候可能会有些学术化、甚至有些误导性的示例中看到。

因此,我想知道除了我下面列出的模式之外,Magento程序员在开发Magento时使用了哪些模式。

需要注意的是,我知道其中一些模式是由于建立在Zend Framework上而存在的,MVC / Front Controller就是其中的两个,

显而易见的是:

工厂(Factory)

$product = Mage::getModel('catalog/product');

单例模式:

$category = Mage::getSingleton('catalog/session');

注册表:

$currentCategory = Mage::registry('current_category');

1
最常用的模式是工厂模式,因为它的具体实现(new Class())已经放在配置文件(xml)中,因此安装新模块时我们不需要编辑任何PHP代码,这得益于工厂模式的使用!! - Mr Coder
很棒的问题,我一直想问这个问题,但一直没有机会提出来 :) - Jonathan Day
2
我希望这个问题能在Magento社区得到广泛关注,因为我已经厌倦了所有来自脚本小子/黑客的Magento抨击,他们如果被一个体面的架构打中,也分辨不出来。 - Jonathan Day
1
我对Magento一无所知,但根据答案判断,它主要使用某种静态前端控制器 ;) - takeshin
2
相关:https://dev59.com/UW855IYBdhLWcg3wvnOE - takeshin
前端控制器是一个很好的例子,把它放到答案中,Tekeshin。 - Joe Mastey
8个回答

17

原型:

Mage:getModel('catalog/product')->getTypeInstance();

事件-观察者对:

# PHP
Mage::dispatchEvent('event_name', array('key'=>$value));

# config.xml
<config>
    <global>
        <events>
            <event_name>
                <observers>
                    <unique_name>
                        <class>Class_Name</class>
                        <method>methodName</method>
                    </unique_name>
                </observers>
            </event_name>
        </events>
    </global>
</config>

对象池:

$id = Mage::objects()->save($object);
$object = Mage::objects($id);

迭代器:

Mage::getModel('catalog/product')->getCollection();

1
我之前没有遇到过对象池。很好的发现 :) - Nick
你能解释一下 Mage:getModel('catalog/product')->getTypeInstance(); 怎么是一个原型模式吗?它似乎使用了工厂模式。 - bogatyrjov

16
Magento中的设计模式详解
1. Model View Controller(MVC)模式
MVC是一种设计模式,用于将业务逻辑、表示和耦合逻辑分离。Magento在很大程度上使用XML作为模板逻辑以及HTML混合PHP文件用于视图展示。模型由Varien ORM支持。大部分业务逻辑发生在模型中,而控制器则将模型数据映射到视图上。
因为Magento的视图很“臃肿”,通常包含很多逻辑,所以视图经常具有一个额外的PHP类(块系统),用于帮助渲染。
2. 前置控制器模式
前置控制器模式确保只有一个入口点。所有请求都会被检查并路由到指定的控制器,然后根据规范进行处理。前置控制器负责初始化环境并将请求路由到指定的控制器。
Magento只有一个入口点(index.php),它将初始化应用程序环境(Mage::app()),然后将请求路由到正确的控制器。
3. 工厂模式
工厂模式负责实例化类。它在Magento的代码库中被广泛使用,并利用Magento的自动加载系统。通过在模块的config.xml中定义别名,可以让工厂知道在哪里可以找到类。
Mage核心类中有各种工厂辅助方法之一是getModel()。它接受一个类别名,然后返回该类的实例。工厂模式将通过统一的方式实例化类,而不是在代码库中散布包含调用。
4. 单例模式
获取类的实例的另一种方法是调用Mage::getSingleton()。它接受一个类别名,并在返回实例之前,检查内部注册表是否已经实例化了这个类 - 这会导致共享实例。必须使用这种方法的一个示例是会话存储,应在整个代码库中共享,而不是每次创建新实例。
5. 注册表模式
所有单例都存储在内部注册表中:全局作用域的容器用于存储数据。它不仅供内部使用。Mage::register($key, $value),::registry($key)和::unregister($key)方法可以分别用于存储、检索和删除注册表中的数据。当无法传递数据时,注册表通常用于在范围之间传输数据。
6. 原型模式
工厂模式(列表中的#3)停止的地方就是原型模式继续的地方。它定义了类的实例可以根据其父类(原型)检索特定的其他类实例。值得注意的一个示例是Mage_Catalog_Model_Product类,它具有getTypeInstance方法,用于检索具有特定子集的特定Mage_Catalog_Model_Product_Type方法和属性,而这些方法和属性并不适用于所有产品。例如,Mage_Downloadable_Model_Product_Type最终扩展了Mage_Catalog_Model_Product_Type。如果您正在遍历订单并想调用可下载产品的特定方法,则需要首先使用原始产品的getTypeInstance方法进行因式分解。
7.对象池模式
对象池模式只是一个盒子,其中包含对象,因此它们不必一遍又一遍地分配和销毁。它在Magento中很少使用,仅用于资源很快会受到限制的繁重任务,例如导入产品。对象池(由Varien_Object_Cache管理)可以通过Mage::objects()访问。
8.迭代器模式
迭代器模式定义了一种共享方式来迭代具有对象的容器。在Magento中,这由Varien_Data_Collection处理,其又使用各种内置PHP类(如ArrayIterator)以获得更多针对数组的面向对象接口。这确保了模型集合将始终具有常见的API可供迭代,而不依赖于实际模型。
9.延迟加载模式
延迟加载确保加载数据被延迟直到实际需要它的时候。这导致使用的资源更少。Magento的延迟加载行为之一是集合的行为。如果您要检索产品集合Mage::getModel('catalog/product')->getCollection(),则仅当您实际访问集合时(例如,通过迭代它或检索找到的模型的计数)才会触及数据库。
10.服务定位器模式
服务定位器模式抽象了某个服务的检索。这允许更改服务而不会破坏任何东西(因为它遵循其抽象基础),但也可以根据其目的自由地获取服务。
Ryan用数据库连接举例。另一个例子是Magento的缓存机制,其中Mage::getCache()是Zend或其他供应商提供的缓存存储的服务定位器。
11.模块模式
熟悉Magento开发的人都会遇到模块模式。它基本上定义了将不同的域分组到单独的模块中,这些模块独立于彼此并可以根据需要插入到主系统中。在理想情况下,模块模式的实现将确保可以删除或交换每个元素。模块模式在PHP中的代表之一是Composer包管理器。
尽管Magento严重依赖于模块化架构,但它并非完全模块化。某些功能与核心密切相关,不易更改。还有超全局Mage核心类的大量使用,引入各种系统范围的依赖关系,不易监控。
12.观察者模式

Magento的事件驱动架构是实现观察者模式的结果。通过定义观察者(或监听器),可以挂接额外的代码,当观察到事件发生时,这些代码将被调用。Magento使用XML数据存储来定义观察者。如果使用Mage :: dispatchEvent($ eventName,$ data)触发事件,则会查询数据存储,并触发适用于$ event的相应观察者。


7
一些更多内容:
事件/监听器:
Mage::dispatchEvent('model_load_before', $params); 

当然,还有MVC,其中视图由XML、PHP类和PHTML模板的组合表示。


你比我快了40秒! - clockworkgeek

6
不要忘记懒加载,这意味着仅在严格必要时才进行数据库访问。例如:
$collection_of_products = Mage::getModel('catalog/product')
->getCollection();
$collection_of_products->addFieldToFilter('sku','n2610');

只有在你尝试访问集合中的项目时,数据库查询才会被执行。


1
我认为Mage_Checkout_Model_Cart和Mage_Sales_Model_Quote之间的关系是“桥接模式”。根据维基百科的定义,桥接旨在“将抽象与其实现解耦,以便两者可以独立变化”。因此,Cart似乎是抽象,而Quote则是实现。

0

服务定位器

Allows overrides or renamed physical resources (e.g. Classes, DB tables, etc)

Mage::getModel('catalog/product')$installer->getTable('customer/address_entity')


3
你显然不理解装饰者模式。"decorateTable" 是一个 JavaScript 函数,它只是向表格添加 CSS 类,例如"odd"、"even"、"first" 或 "last"。装饰者模式可以在不创建子类的情况下,为对象添加功能。 - Denis

0
以下是设计模式: 1. 模型视图控制。
  1. 单例

  2. 工厂

  3. 注册表

  4. 前置控制器

  5. 迭代器

  6. 延迟加载

  7. 观察者(事件)


-2
一般来说,在我看来,Magento 使用自己独特的大多数模式实现,因此不应该在它们之间进行太多比较。
例如,过去我曾将工厂创建模式视为一个类,用于处理实例化组类。在 Magento 中,合并的配置 XML 文件存储所有模型、块和助手路径,以便在开发过程中开发人员仅指定路径斜杠和实际类名的唯一标识符。单例模式和注册表模式也与预期不同。

问题非常清楚,需要详细说明Magento中使用的所有可能的设计模式。答案提到的只是描述观点,而不是答案。 - Kamesh Jungi

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接