以下代码来自教程(http://net.tutsplus.com/php/creating-a-php5-framework-part-1/),而不是我的。
我对此代码有几个问题......
我只想弄清楚我是否应该在自己的MVC框架实现中使用这种设计模式。谢谢!
<?php
/**
* The PCARegistry object
* Implements the Registry and Singleton design patterns
* @version 0.1
* @author Michael Peacock
*/
class PCARegistry {
/**
* Our array of objects
* @access private
*/
private static $objects = array();
/**
* Our array of settings
* @access private
*/
private static $settings = array();
/**
* The frameworks human readable name
* @access private
*/
private static $frameworkName = 'PCA Framework version 0.1';
/**
* The instance of the registry
* @access private
*/
private static $instance;
/**
* Private constructor to prevent it being created directly
* @access private
*/
private function __construct()
{
}
/**
* singleton method used to access the object
* @access public
* @return
*/
public static function singleton()
{
if( !isset( self::$instance ) )
{
$obj = __CLASS__;
self::$instance = new $obj;
}
return self::$instance;
}
/**
* prevent cloning of the object: issues an E_USER_ERROR if this is attempted
*/
public function __clone()
{
trigger_error( 'Cloning the registry is not permitted', E_USER_ERROR );
}
/**
* Stores an object in the registry
* @param String $object the name of the object
* @param String $key the key for the array
* @return void
*/
public function storeObject( $object, $key )
{
require_once('objects/' . $object . '.class.php');
self::$objects[ $key ] = new $object( self::$instance );
}
/**
* Gets an object from the registry
* @param String $key the array key
* @return object
*/
public function getObject( $key )
{
if( is_object ( self::$objects[ $key ] ) )
{
return self::$objects[ $key ];
}
}
/**
* Stores settings in the registry
* @param String $data
* @param String $key the key for the array
* @return void
*/
public function storeSetting( $data, $key )
{
self::$settings[ $key ] = $data;
}
/**
* Gets a setting from the registry
* @param String $key the key in the array
* @return void
*/
public function getSetting( $key )
{
return self::$settings[ $key ];
}
/**
* Gets the frameworks name
* @return String
*/
public function getFrameworkName()
{
return self::$frameworkName;
}
}
?>
答案 0 :(得分:25)
该文章声称它正在使用“注册表设计模式”;这是该行业设计的通用名称吗?
是的,但实施情况可能明显不同。基本上,注册表是共享对象的容器。在真正的基本版本中,您可以使用数组。因此,变量$GLOBALS
可以称为注册表。
还有其他类似的模式会是更好的选择吗?
注册表有两种变体。有全球注册表(这是最常见的,这是一个例子)。还有一个本地注册表。本地注册表将传递给需要它的对象,而不是通过全局符号(静态类,单例等)获得。本地注册表具有较低程度的耦合,但也略微抽象,因此存在权衡。
您还可以进一步使用完全依赖项注入,您可以将所有依赖项显式传递给需要它们的对象。在较大的应用程序中,这可能有点单调乏味。您可以将它与依赖注入容器耦合,该容器是一段“知道”哪些类具有依赖关系的代码。这比本地注册表更复杂,但耦合程度非常低。
这种模式被认为是在MVC框架环境中实现的良好实践吗?
这是常见的做法。判断是好还是坏。就个人而言,我愿意接受一些复杂性以换取脱钩,但是ymmv。
答案 1 :(得分:5)
我认为,一般来说,真的没有像“糟糕的模式”这样的东西。话虽这么说,一些技术应该比其他技术更加谨慎使用,而全球注册表的概念通常不够优雅。问题在于给定对象之间的依赖关系是通过基于名称的寻址来处理的,这类似于简单地使用全局变量,而不是通过提供依赖关系来实现策略的间接 - 这通常被称为依赖注入。
这如何影响软件的重用和灵活性实际上非常清楚。考虑各种请求处理程序,它与OAuth2提供程序集成以进行身份验证。如果您定义一个具有良好定义的接口的对象来向此OAuth2提供程序发出请求,您可以通过创建另一个实现相同接口的对象来更改提供程序。
现在让我们说,为了讨论,你的第一个实现需要访问Facebook。但接下来的一周,你决定你也应该支持雅虎,雅虎实施OAuth2的方式比Facebook更接近规范,实际上在授权令牌请求中使用JSON而不是名称值对。最重要的是,有不同的URL和密钥对以及需要保留的东西。
如果您使用注册表模式或服务定位器模式按名称查找身份验证提供程序,那么您现在遇到了问题。您需要复制代码并对其进行微小更改,以便您可以同时支持这两个代码,或者找到另一个解决方案,例如传递密钥并在所有位置添加哈希表以查找所有这些元素并检测这些差异。同时,如果使用依赖注入,则可以简单地创建身份验证提供程序的另一个实现,该实现实现解析身份验证令牌的微小差异,并创建使用该对象的请求处理程序的新实例已经过测试,然后将其部署到新位置。
间接节省了您的工作,减少了必要的代码量,最终使您的软件更便宜,更好,更快。
话虽如此,有时候这两种模式不能直接互换。比方说,您正在构建一种将事件处理程序附加到XML文档节点的框架。您可以使用XPath或JQuery的CSS选择器实现来描述XML文档中节点的位置。但是为了附加事件处理程序,您还需要引用一些代码。最好,你会引用一些对象的某种方法 - 好吧,没有给它命名就找不到这个“某个对象”,所以现在你需要一个服务定位器,这样你就可以按名称查找了。但请记住,即使在这个例子中,没有任何规定名称必须是全球。
在此处调用本地服务定位器或本地注册表是解决此类问题的合理解决方案。如果同一个应用程序中有两个注册表实例,则可以偶尔减轻上述一些重用问题。