magento its architecture is sometimes deemed overly engineered. if we look at it from a helicopter view, commonly used design patterns are easily spotted. here are 12 of them.
a software design pattern is a reusable solution to an often occurring problem. this doesn’t mean that software is better if it
has more design patterns. instead, a good software engineer should be able to spot the problem and implement the pattern instead of introducing implementations without purpose. the earlier behavior is leadingly noticeable in magento, where most if not all
design pattern-implementations have a purpose.
this is a compilation of an article-series which originally appeared on ryan
street’s blog (@ryanstreet).
model view controller, mvc for short, is a design pattern where business, presentation and coupling logic are separated. magento heavily utilizes xml as templating-logic and html mixed with php files for its views.
models are backed by varien’s orm. most business logic happens in the models whereas the controllers map the model-data to the views.
because magento its views are “fat” – they often contain a lot of logic – its not rare that views have an additional php class (the block system) which will help with rendering.
the front controller pattern makes sure that there is one and only one point of entry. all requests are investigated, routed to the designated controller and then processed accordingly to the specification. the
front controller is responsible of initializing the environment and routing requests to designated controllers.
magento has only one point of entry (<code>index.php</code>) which will initialize the application environment (<code>mage::app()</code>) and route
the request to the correct controller.
as implied by the name, the factory pattern is responsible of factorizing (instantiating) classes. it’s widely used through the magento code base and leverages the autoloading system in magento. by defining an alias
in a module its <code>config.xml</code> you are letting the factory know where it can find classes.
there are various factory-helper methods in the <code>mage</code> core class and one of them is <code>getmodel()</code>. it accepts an alias for
a class and will then return an instance of it. instead of having <code>include</code> calls scattered through the code base, the factory pattern will instantiate classes in an uniform way.
another way to retrieve an instance of a class, is to call <code>mage::getsingleton()</code>. it accepts a class alias and before returning an instance, it checks the internal registry
whether this class has already been instantiated before – this results in a shared instance. an example of where this is mandatory, is the session storage which should be shared through the code base instead of creating it anew every time.
all the singletons are stored in the internal registry: a global scoped container for storing data. it is not only for internal use. the <code>mage::register($key, $value)</code>,<code>::registry($key)</code> and <code>::unregister($key)</code> methods
can be respectively used for storing, retrieving and removing data from the registry. the registry is often used for transferring data between scopes when they cannot be passed on, otherwise.
where the factory pattern (#3 on our list) stops, is where the prototype pattern continues. it defines that instances of classes can retrieve a specific other class instance depending on its parent class (the prototype).
a notable example is the <code>mage_catalog_model_product</code> class which has a <code>gettypeinstance</code> method to retrieve the specific<code>mage_catalog_model_product_type</code> with
a specific subset of methods and properties not applicable to all products.
for example, the <code>mage_downloadable_model_product_type</code> ultimately extends the <code>mage_catalog_model_product_type</code>. if you are
iterating over an order and want to call a specific method of a downloadable product, you will need to factorize it first with the <code>gettypeinstance</code> method of the original product.
the object pool pattern is simply a box with objects so that they do not have to be allocated and destroyed over and over again. it’s not used a lot in magento other than for heavy tasks where resources can get
limited soon, like importing products. the object pool (managed by <code>varien_object_cache</code>) can be accessed with <code>mage::objects()</code>.
the iterator pattern defines that there is a shared way to iterate over a container with objects. in magento, this is handled by the <code>varien_data_collection</code> which
on its turn uses various baked-in php classes (like <code>arrayiterator</code>) for having a more oo-interface to arrays. this ensures that model-collections will always have a common api to iterate over without being dependent
of the actual models.
lazy loading ensures that loading data is delayed until the point when it is actually needed. this results in less resources being used. one of the lazy loading behaviors of magento is that of collections. if you
were to retrieve a collection of products with <code>mage::getmodel('catalog/product')->getcollection()</code>, the database will only be touched when you actually access the collection by, for example, iterating over it or
retrieving the count of models found.
the service locator pattern abstracts away the retrieval of a certain service. this allows for changing the service without breaking anything (as it adheres to its abstract foundation) but also fetching the service
as seen fit for its purpose.
ryan exemplifies this with database connections. another example is that
of magento its caching mechanism where <code>mage::getcache()</code> is a service locator by-proxy for the cache storage
supplied by zend or other vendors.
anyone familiar with magento development has stumbled upon the module pattern. it basically defines that different domains are grouped into separate modules which function independent of each other and can be plugged-in
to the main system as deemed appropriate. in an ideal situation, an implementation of the module pattern would make sure that each element can be removed or swapped. one of the protagonists of the module pattern in php is the composer
package manager.
though magento heavily relies on a modular architecture, its not modular to the bone. certain functionality is heavily tied to the
core and can not be easily changed. there is also the heavy usage of the super-global <code>mage</code> core-class which introduces all sorts of system-wide dependencies not easily overseen.
magento its event-driven architecture is a result of an implementation of the observer pattern. by defining observers (or listeners), extra code can be hooked which will be called upon as the observed event fires.
magento uses its xml-data storage to define observers. if an event is fired with <code>mage::dispatchevent($eventname, $data)</code>, the data storage will be consulted and the appropriate observers for <code>$event</code> will
be fired.
in addition to using modules, events can be used to customize existing logic without touching the existing code.
hopefully these 12 design patterns, give you a bit better understanding of the architectural decisions made in magento. not all design patterns found in magento are implemented as defined by the original
literature. this is perfectly fine, because design patterns are there to help with solving common problems as seen fit, instead of deploying verbatim implementations.
原文位址:http://magenticians.com/12-design-patterns-magento