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

2022-08-30 23:12:11

以下代码来自教程(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;
}


}

?>

答案 1

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

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

有没有另一个类似的模式,这将是一个更好的选择?

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

您还可以更进一步,使用完整的依赖项注入,其中将所有依赖项显式传递给需要它们的对象。这在较大的应用程序中可能有点乏味。您可以将其与依赖项注入容器结合使用,该容器是一段“知道”哪些类具有哪些依赖项的代码。这甚至比本地注册表更复杂,但耦合程度非常低。

此模式是否被视为在 MVC 框架上下文中实现的良好做法?

这是常见的做法。如果它是好是坏是一个判断电话。就个人而言,我愿意接受一些复杂性来换取解耦,但是ymmv。


答案 2

我认为,一般而言,实际上并不存在“不良模式”之类的东西。话虽如此,某些技术应该比其他技术更谨慎地使用,而全球注册表的概念往往不那么优雅。它的问题是,给定对象之间的依赖关系是通过基于名称的寻址来处理的,这类似于简单地使用全局变量,而不是通过提供依赖关系来间接制定策略 - 这就是通常所说的依赖注入

这如何影响软件的重用和灵活性实际上非常清楚。考虑一个与 OAuth2 提供程序集成以进行身份验证的各种请求处理程序。如果定义一个对象具有明确定义的接口,用于向此 OAuth2 提供程序发出请求,则将来可以通过创建另一个实现相同接口的对象来更改提供程序。

现在,假设为了讨论,您的第一个实现需要访问Facebook。但是下周,你决定你也应该支持雅虎,雅虎以比Facebook更严格遵循规范的方式实现OAuth2,实际上在授权令牌请求中使用JSON而不是名称值对。最重要的是,有不同的URL和密钥对,以及不需要保留的内容。

好吧,如果您使用注册表模式或服务定位器模式按名称查找身份验证提供程序,那么您现在遇到了问题。您需要复制代码并对其进行细微更改,以便可以同时支持两者,或者找到另一种解决方案,例如传递密钥并在所有位置添加哈希表,以查找所有这些元素并检测这些差异。同时,如果您使用了依赖关系注入,则只需创建身份验证提供程序的另一个实现,该实现解析身份验证令牌的微小差异,并创建一个使用该对象且已经过测试的请求处理程序的新实例,然后将其部署到新位置。

间接寻址节省了您的工作,减少了所需的代码量,并最终使您的软件更便宜,更好,更快。

话虽如此,有时这两种模式不能直接互换。例如,假设您正在构建一种框架,它将事件处理程序附加到XML文档的节点。您可以使用 XPath 或 JQuery 的 CSS 选择器实现来描述 XML 文档中节点的位置。但是,为了附加事件处理程序,您还需要引用一些代码。最好是,您将引用某个对象的某个方法 - 好吧,如果不给它一个名称,就无法找到这个“某个对象”,所以现在你需要一个服务定位器,这样你就可以按名称查找内容。但请记住,即使在此示例中,也没有规定名称必须是全局的。

创建本地服务定位器或此处调用的本地注册表是解决此类性质问题的合理解决方案。如果同一应用程序中可以有两个注册表实例,则上述一些重用问题有时可以得到缓解。


推荐