注册表设计模式...好还是坏?[英] Registry design pattern...good or bad?

本文是小编为大家收集整理的关于注册表设计模式...好还是坏?的处理/解决方法,可以参考本文帮助大家快速定位并解决问题,中文翻译不准确的可切换到English标签页查看源文。

问题描述

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


}

?>

推荐答案

本文声称它正在使用"注册表设计模式";这是行业中这个设计的通用名称吗?

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

还有其他类似的模式可以是更好的选择吗?

注册表有两种变体.有全球注册表(最常见,这是一个例子).还有一个本地注册表.本地注册表传递给需要它的对象,而不是通过全局符号(静态类,单例等)获得的对象.本地注册表的耦合程度较低,但也更加抽象,因此在那里有一个权衡.

您也可以进一步走,并使用完全依赖注入,在这里您将所有依赖项明确地传递给需要它们的对象.在较大的应用程序中,这可能有些乏味.您可以将其与依赖项注入容器相结合,这是"知道"哪个类别的代码.这比本地注册表更复杂,但耦合程度非常低.

在MVC框架的背景下,这种模式是否是实施的好实践?

这是常见的做法.如果是好是坏,那就是判断电话.就我个人而言,我愿意接受一些复杂性,但YMMV.

其他推荐答案

我认为,从一般而言, 都没有像"不良模式".话虽如此,某些技术应该比其他技术更少于其他技术,而A Global 注册表的概念通常不如优雅.它的问题在于,给定对象之间的依赖项是通过基于名称的地址来处理的,这类似于简单地使用全局变量,而不是通过提供依赖性来进行策略的间接化 - 这通常称为> 依赖注入.

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

现在,假设您的第一个实现需要访问Facebook.但是下周,您决定还应该支持Yahoo,后者以比Facebook更接近规范的方式实现OAuth2,实际上在授权令牌请求中使用JSON而不是名称值对.最重要的是,有不同的URL和键以及需要保留的内容.

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

间接方向节省了您的工作,减少了必要的代码数量,并最终使您的软件更便宜,更好,更快.

话虽如此,有时两种模式不是直接可互换的.假设您正在构建一种将事件处理程序附加到XML文档节点的框架.您使用XPath或JQuery的CSS选择器实现了XML文档中节点的位置.但是,为了附加事件处理程序,您还需要参考一些代码.最好是,您将参考某些对象的某些方法 - 嗯,没有办法在不给它的情况下找到此"某些对象",因此现在您需要服务定位器,因此您可以按名称查找内容.但是请记住,即使在此示例中,也没有规定该名称必须为 global .

在这里创建本地服务定位器或本地注册表,是解决这种性质问题的合理解决方案.如果在同一应用程序中可以有两个注册表的实例,则有时可以减轻上述重复使用问题.

本文地址:https://www.itbaoku.cn/post/627595.html

问题描述

The following code is from a tutorial (http://net.tutsplus.com/php/creating-a-php5-framework-part-1/), not mine.

I have a few questions about this code...

  • The article claims it is using the "registry design pattern"; is that the universal name for this design in the industry?
  • Is there another similar patter out there that would be a better option?
  • Is this pattern considered to be good practice to implement in the context of an MVC framework?

I just want to figure out if I should use this design pattern in my own implementation of a MVC framework. Thanks!

<?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;
}


}

?>

推荐答案

The article claims it is using the "registry design pattern"; is that the universal name for this design in the industry?

Yes, but the implementation could obviously differ. Basically, a registry is a container for shared objects. In the really basic version, you could use an array. As such, the variable $GLOBALS could be called a registry.

Is there another similar patter out there that would be a better option?

There are two variations of a registry. There is the global registry (Which is far the most common, and which this is an example of). And there is a local registry. A local registry is passed to objects that need it, rather than obtained through a global symbol (static class, singleton etc.). A local registry has a lower degree of coupling, but is also slightly more abstract, so there is a tradeoff there.

You can also go even further and use full dependency injection, where you explicitly pass all the dependencies to the objects that need them. This can be a bit tedious in larger applications. You can couple this with a dependency injection container, which is a piece of code that "knows" which dependencies which classes have. This is even more complex than a local registry, but has a very low degree of coupling.

Is this pattern considered to be good practice to implement in the context of an MVC framework?

It's common practise. If it's good or bad is a judgement call. Personally I'm willing to accept some complexity in return of decoupling, but ymmv.

其他推荐答案

I'm of the opinion that generically speaking, there isn't really such a thign as a "bad pattern". That being said, some techniques should be used more sparingly than others, and the notion of a global registry is one which is often less than elegant. The issue with it is that dependencies between given objects are handled through name-based addressing, which is akin to simply using global variables, rather than by the indirection of strategizing by having dependencies be provided — which is what's commonly referred to as dependency injection.

How this can impact the reuse and flexibility of software is actually very clear. Consider a request handler of sorts which integrates with an OAuth2 provider for authentication. If you define an object with a well defined interface for making requests to this OAuth2 provider, you have the ability to change the provider in the future by creating another object which implements the same interface.

Now let's say for discussion sake your first implementation needs to access Facebook. But then next week, you make the decision that you should also support Yahoo, who implements OAuth2 in a way which follows the specification more closely than Facebook does, actually using JSON in the authorization token request rather than name value pairs. And on top of that, there are different pairs of URLs and Keys and whatnot which need to be kept.

Well if you were looking up your authentication provider by name using the registry pattern or service locator patterns, you now have a problem. You need to either copy the code and make the minor changes to it so you can support both at once, or find another solution such as passing keys around and adding hash tables in all locations to find all these elements and detect these variances. Meanwhile if you used dependency injection, you can simply create another implementation of your authentication provider which implements the minor variance of parsing the authentication token, and create a new instance of your request handler which uses that object and has already been tested, and then deploy it to a new location.

The indirection saved you work, reduced the amount of code necessary, and ultimately made your software cheaper, better and faster.

With that said, there are times when the two patterns are not directly interchangeable. Let's say for instance you are building a sort of framework which attaches event handlers to nodes of an XML document. You describe the locations of nodes in an XML document using XPath or JQuery's implementation of CSS selectors. But in order to attach an event handler, you also need to refer to some code. Preferably, you'll refer to some method of some object — well, there's no way to find this "some object" without giving it a name, so now you need a service locator, so you can look things up by name. But do keep in mind that even in this example, there's nothing stipulating that the name must be global.

Creating a local service locator, or local registry as you are calling it here, is a reasonable solution to a problem of this nature. If there can be two instances of the registry in the same application, some of the aforementioned reuse problems can occasionally be mitigated.