注册表设计模式...好还是不好?

17
下面的代码来自一个教程(http://net.tutsplus.com/php/creating-a-php5-framework-part-1/),不是我的。
我有几个问题关于这个代码...
• 文章声称它使用了"注册表设计模式"; 这是行业中通用的名称吗?
• 是否有其他类似的模式是更好的选择?
• 在MVC框架的上下文中实现这种模式是否被认为是良好的实践?
我只是想弄清楚是否应该在我自己实现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;
}


}

?>

哈哈...我被点赞了,然后又被踩了。看来我的问题没能得到大家的认同。 - Jarred
2个回答

26

这篇文章声称它正在使用“注册表设计模式”;这是行业中通用的名称吗?

是的,但实现显然可能不同。基本上,注册表是一种共享对象的容器。在最简单的版本中,您可以使用数组。因此,变量$GLOBALS可以称为注册表。

是否有另一个类似的模式可以作为更好的选择?

有两种注册表的变体。有全局注册表(这是最常见的,并且这是一个示例)。还有本地注册表。本地注册表传递给需要它的对象,而不是通过全局符号(静态类、单例等)获取。本地注册表具有较低程度的耦合度,但也稍微抽象一些,因此存在权衡。

您还可以进一步使用完全依赖注入,其中您明确地将所有依赖项传递给需要它们的对象。在较大的应用程序中,这可能有点繁琐。您可以将其与依赖注入容器相结合,后者是一段“知道”哪些依赖关系属于哪些类的代码。这比本地注册表更复杂,但具有很低的耦合度。

在MVC框架的上下文中,这种模式是否被认为是实现良好的实践?

它是常见的做法。它是好还是坏取决于判断。个人而言,我愿意接受一些复杂性以换取解耦,但您的情况可能不同。


6
我认为,普遍而言,“坏的模式”并不存在。但是,有些技术应该比其他技术更加谨慎地使用,全局注册表的概念通常不太优雅。问题在于,给定对象之间的依赖关系是通过基于名称的寻址处理的,这类似于仅仅使用全局变量,而不是通过提供依赖项来进行策略性间接引用,这通常被称为“依赖注入”。
这如何影响软件的重用和灵活性实际上非常清楚。考虑一种请求处理程序,它与OAuth2提供程序集成以进行身份验证。如果您定义一个具有良好定义的接口的对象,用于向此OAuth2提供程序发送请求,则可以通过创建另一个实现相同接口的对象来在将来更改提供程序。
现在假设,举个例子,您的第一个实现需要访问Facebook。但是下周,您决定还应支持Yahoo,后者以比Facebook更紧密地遵循规范的方式实现了OAuth2,实际上在授权令牌请求中使用JSON而不是名称值对。此外,需要保留不同的URL和键对等等。
如果您使用注册表模式或服务定位器模式按名称查找身份验证提供程序,则现在存在问题。您需要复制代码并对其进行微小更改,以便同时支持两者,或者找到另一种解决方案,例如传递密钥并在所有位置添加哈希表以查找所有这些元素并检测这些差异。与此同时,如果您使用依赖注入,则可以简单地创建另一个实现身份验证提供程序的对象,该对象实现解析身份验证令牌的微小变化,并创建一个已经经过测试的新请求处理程序实例,该实例使用该对象,然后部署到新位置。
间接引用可以节省您的工作量,减少必要的代码量,并最终使您的软件更加便宜、更好、更快。
话虽如此,有时两种模式并不是直接可互换的。例如,假设您正在构建一种框架,该框架将事件处理程序附加到XML文档的节点上。您使用XPath或JQuery的CSS选择器实现来描述节点的位置。但是为了附加事件处理程序,您还需要引用一些代码。最好,您将引用某个对象的某个方法 - 没有办法找到此“某个对象”而不给它命名,因此现在您需要一个服务定位器,以便按名称查找事物。但请记住,即使在这个例子中,也没有规定名称必须是全局的。
创建本地服务定位器或本地注册表是解决这种问题的合理解决方案。如果同一应用程序中可以有两个注册表实例,则可以偶尔减轻一些前述的重用问题。

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